tranfi 0.0.2 → 0.2.0
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/LICENSE +177 -21
- package/NOTICE +8 -0
- package/README.md +627 -0
- package/app/assets/index-6quYZ5Ap.css +5 -0
- package/app/assets/index-BIAIKnrp.js +160 -0
- package/app/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
- package/app/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
- package/app/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
- package/app/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
- package/app/index.html +13 -0
- package/binding.gyp +121 -0
- package/csrc/arena.c +93 -0
- package/csrc/batch.c +976 -0
- package/csrc/buffer.c +154 -0
- package/csrc/cJSON.c +3386 -0
- package/csrc/cJSON.h +316 -0
- package/csrc/codec_csv.c +1951 -0
- package/csrc/codec_jsonl.c +1086 -0
- package/csrc/codec_table.c +248 -0
- package/csrc/codec_text.c +447 -0
- package/csrc/compiler.c +130 -0
- package/csrc/config.h +21 -0
- package/csrc/date_utils.h +94 -0
- package/csrc/dsl.c +5417 -0
- package/csrc/dsl.h +22 -0
- package/csrc/expr.c +1553 -0
- package/csrc/expr.h +58 -0
- package/csrc/internal.h +539 -0
- package/csrc/ir.c +166 -0
- package/csrc/ir.h +208 -0
- package/csrc/ir_schema.c +75 -0
- package/csrc/ir_serialize.c +166 -0
- package/csrc/ir_sql.c +1822 -0
- package/csrc/ir_validate.c +576 -0
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +1241 -0
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +283 -0
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +255 -0
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +248 -0
- package/csrc/op_cast.c +523 -0
- package/csrc/op_clip.c +99 -0
- package/csrc/op_date_trunc.c +355 -0
- package/csrc/op_datetime.c +394 -0
- package/csrc/op_derive.c +216 -0
- package/csrc/op_diff.c +250 -0
- package/csrc/op_ewma.c +222 -0
- package/csrc/op_explode.c +206 -0
- package/csrc/op_fill_down.c +235 -0
- package/csrc/op_fill_null.c +268 -0
- package/csrc/op_filter.c +181 -0
- package/csrc/op_frequency.c +721 -0
- package/csrc/op_grep.c +181 -0
- package/csrc/op_group_agg.c +1956 -0
- package/csrc/op_hash.c +159 -0
- package/csrc/op_head.c +84 -0
- package/csrc/op_interpolate.c +445 -0
- package/csrc/op_join.c +2902 -0
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +419 -0
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +242 -0
- package/csrc/op_normalize.c +510 -0
- package/csrc/op_onehot.c +457 -0
- package/csrc/op_pivot.c +1754 -0
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +3044 -0
- package/csrc/op_rename.c +129 -0
- package/csrc/op_replace.c +354 -0
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +158 -0
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +340 -0
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +95 -0
- package/csrc/op_sort.c +819 -0
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +151 -0
- package/csrc/op_split_data.c +119 -0
- package/csrc/op_stack.c +271 -0
- package/csrc/op_stats.c +875 -0
- package/csrc/op_step.c +333 -0
- package/csrc/op_tail.c +105 -0
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +357 -0
- package/csrc/op_trim.c +138 -0
- package/csrc/op_unique.c +1343 -0
- package/csrc/op_unpivot.c +193 -0
- package/csrc/op_validate.c +648 -0
- package/csrc/op_window.c +591 -0
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +1088 -0
- package/csrc/recipes.c +104 -0
- package/csrc/recipes.h +27 -0
- package/csrc/report.c +506 -0
- package/csrc/report.h +22 -0
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +348 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +291 -0
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +218 -0
- package/napi_api.c +534 -0
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +64 -59
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +190 -0
- package/src/engines/duckdb.js +142 -0
- package/src/index.js +925 -0
- package/src/memory_policy.js +411 -0
- package/src/native.js +18 -0
- package/src/pipeline.js +709 -0
- package/src/recipe_json.js +80 -0
- package/src/server.js +279 -0
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +21 -0
- package/wasm/index.js +732 -0
- package/wasm/package.json +1 -0
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/dist/bundle.js +0 -1
- package/index.html +0 -18
- package/src/app.css +0 -169
- package/src/app.js +0 -203
- package/src/app.vue +0 -250
- package/src/bulma-input.vue +0 -110
- package/src/common-inputs.js +0 -28
- package/src/main.js +0 -20
- package/src/transforms.js +0 -166
- package/webpack.config.js +0 -108
|
@@ -0,0 +1,1156 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { stringifyRecipe } = require('../src/recipe_json.js')
|
|
4
|
+
|
|
5
|
+
const { TranfiTransformError } = require('../src/transform_error.js')
|
|
6
|
+
|
|
7
|
+
const VIEW_FLOAT32 = 0x0101
|
|
8
|
+
const VIEW_FLOAT64 = 0x0102
|
|
9
|
+
const SCHEMA_INPUT = 1
|
|
10
|
+
const SCHEMA_OUTPUT = 2
|
|
11
|
+
const NO_HOST_CANCEL = 0xffffffff
|
|
12
|
+
|
|
13
|
+
const LIMIT_FIELDS = [
|
|
14
|
+
'maxRecipeBytes',
|
|
15
|
+
'maxPlanBytes',
|
|
16
|
+
'maxJsonDepth',
|
|
17
|
+
'maxObjectKeys',
|
|
18
|
+
'maxSteps',
|
|
19
|
+
'maxInputColumns',
|
|
20
|
+
'maxOutputColumns',
|
|
21
|
+
'maxCategoriesPerColumn',
|
|
22
|
+
'maxTotalCategories',
|
|
23
|
+
'maxStringBytes',
|
|
24
|
+
'maxDecodedStringBytes',
|
|
25
|
+
'maxAnalyzerRows',
|
|
26
|
+
'maxAnalyzerInputBytes',
|
|
27
|
+
'maxResidentStateBytes',
|
|
28
|
+
'maxSpillBytes',
|
|
29
|
+
'maxApplyRows',
|
|
30
|
+
'maxApplyInputBytes',
|
|
31
|
+
'maxOutputElementsPerCall',
|
|
32
|
+
'maxAllocationBytes',
|
|
33
|
+
'maxAllocationsPerSession',
|
|
34
|
+
'maxLiveHandles',
|
|
35
|
+
'maxRetiredHandleSlots'
|
|
36
|
+
]
|
|
37
|
+
const LIMIT_FIELD_SET = new Set(LIMIT_FIELDS)
|
|
38
|
+
|
|
39
|
+
const ERROR_NAMES = {
|
|
40
|
+
100: 'invalid prepared-transform argument',
|
|
41
|
+
101: 'invalid prepared-transform recipe',
|
|
42
|
+
102: 'prepared-transform schema mismatch',
|
|
43
|
+
103: 'insufficient data to finalize prepared transform',
|
|
44
|
+
104: 'prepared-transform resource limit exceeded',
|
|
45
|
+
105: 'unsupported prepared-transform version',
|
|
46
|
+
106: 'corrupt prepared-transform plan',
|
|
47
|
+
107: 'prepared-transform numeric domain error',
|
|
48
|
+
108: 'unknown prepared-transform category',
|
|
49
|
+
109: 'prepared transform cancelled',
|
|
50
|
+
110: 'prepared-transform allocation failed',
|
|
51
|
+
111: 'prepared-transform I/O failed',
|
|
52
|
+
112: 'prepared-transform object is closed or terminal',
|
|
53
|
+
113: 'unsupported prepared-transform runtime',
|
|
54
|
+
199: 'internal prepared-transform error'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createTransformAPI(wasm) {
|
|
58
|
+
var encoder = new TextEncoder()
|
|
59
|
+
var decoder = new TextDecoder()
|
|
60
|
+
var cancelPolls = new Map()
|
|
61
|
+
var nextCancelSlot = 1
|
|
62
|
+
var safeLimitProfile = null
|
|
63
|
+
|
|
64
|
+
wasm.tfTransformCancelPoll = function(slot) {
|
|
65
|
+
var poll = cancelPolls.get(slot >>> 0)
|
|
66
|
+
if (!poll) return false
|
|
67
|
+
if (poll.observer) {
|
|
68
|
+
var observer = poll.observer
|
|
69
|
+
poll.observer = null
|
|
70
|
+
observer()
|
|
71
|
+
}
|
|
72
|
+
return Atomics.load(poll.flag, 0) !== 0
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function dataView() {
|
|
76
|
+
return new DataView(wasm.HEAPU8.buffer)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function readU32(offset) {
|
|
80
|
+
return dataView().getUint32(offset, true)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function writeU32(offset, value) {
|
|
84
|
+
dataView().setUint32(offset, value >>> 0, true)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readU64(offset) {
|
|
88
|
+
var value = dataView().getBigUint64(offset, true)
|
|
89
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
90
|
+
throw new RangeError('transform limit exceeds JavaScript safe integer range')
|
|
91
|
+
}
|
|
92
|
+
return Number(value)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function writeU64(offset, value) {
|
|
96
|
+
dataView().setBigUint64(offset, BigInt(value), true)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function alloc(size, alignment) {
|
|
100
|
+
alignment = alignment || 1
|
|
101
|
+
if (!Number.isSafeInteger(size) || size < 0
|
|
102
|
+
|| !Number.isSafeInteger(alignment) || alignment <= 0
|
|
103
|
+
|| size > 0xffffffff - alignment + 1) {
|
|
104
|
+
throw resourceLimit('WASM transport allocation exceeds wasm32')
|
|
105
|
+
}
|
|
106
|
+
var actualSize = Math.max(1, size + alignment - 1)
|
|
107
|
+
var base = wasm._malloc(actualSize) >>> 0
|
|
108
|
+
if (!base) throw new TranfiTransformError(110, 'WASM allocation failed')
|
|
109
|
+
var pointer = Math.ceil(base / alignment) * alignment
|
|
110
|
+
return { base: base >>> 0, pointer: pointer >>> 0, size: size >>> 0 }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function free(owner) {
|
|
114
|
+
if (owner && owner.base) wasm._free(owner.base)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function allocBytes(bytes, alignment, cancelToken) {
|
|
118
|
+
throwIfCancelled(cancelToken)
|
|
119
|
+
var owner = alloc(bytes.byteLength, alignment || 1)
|
|
120
|
+
try {
|
|
121
|
+
for (var offset = 0; offset < bytes.byteLength; offset += 65536) {
|
|
122
|
+
throwIfCancelled(cancelToken)
|
|
123
|
+
var end = Math.min(offset + 65536, bytes.byteLength)
|
|
124
|
+
wasm.HEAPU8.set(bytes.subarray(offset, end), owner.pointer + offset)
|
|
125
|
+
}
|
|
126
|
+
throwIfCancelled(cancelToken)
|
|
127
|
+
return owner
|
|
128
|
+
} catch (error) {
|
|
129
|
+
free(owner)
|
|
130
|
+
throw error
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function allocWord() {
|
|
135
|
+
var owner = alloc(4, 4)
|
|
136
|
+
writeU32(owner.pointer, 0)
|
|
137
|
+
return owner
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function raw(name, args) {
|
|
141
|
+
var types = new Array(args.length).fill('number')
|
|
142
|
+
return wasm.ccall(name, 'number', types, args) >>> 0
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function destroyHandle(handle) {
|
|
146
|
+
return raw('tf_wasm_transform_handle_destroy', [handle >>> 0])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function errorFromHandle(code, handle) {
|
|
150
|
+
var message = ERROR_NAMES[code] || ('prepared transform failed with code ' + code)
|
|
151
|
+
handle = handle >>> 0
|
|
152
|
+
if (!handle) return new TranfiTransformError(code, message)
|
|
153
|
+
var sizeOwner = null
|
|
154
|
+
var messageOwner = null
|
|
155
|
+
try {
|
|
156
|
+
sizeOwner = allocWord()
|
|
157
|
+
if (raw('tf_wasm_transform_error_message_size', [handle, sizeOwner.pointer]) === 0) {
|
|
158
|
+
var length = readU32(sizeOwner.pointer)
|
|
159
|
+
messageOwner = alloc(length, 1)
|
|
160
|
+
if (raw('tf_wasm_transform_error_message_copy', [
|
|
161
|
+
handle, messageOwner.pointer, length
|
|
162
|
+
]) === 0) {
|
|
163
|
+
message = decoder.decode(wasm.HEAPU8.slice(
|
|
164
|
+
messageOwner.pointer, messageOwner.pointer + length
|
|
165
|
+
))
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} finally {
|
|
169
|
+
free(messageOwner)
|
|
170
|
+
free(sizeOwner)
|
|
171
|
+
destroyHandle(handle)
|
|
172
|
+
}
|
|
173
|
+
return new TranfiTransformError(code, message)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function callWithError(name, args) {
|
|
177
|
+
var errorOwner = allocWord()
|
|
178
|
+
try {
|
|
179
|
+
var code = raw(name, args.concat([errorOwner.pointer]))
|
|
180
|
+
if (code !== 0) throw errorFromHandle(code, readU32(errorOwner.pointer))
|
|
181
|
+
} finally {
|
|
182
|
+
free(errorOwner)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function callForHandle(name, args) {
|
|
187
|
+
var outputOwner = allocWord()
|
|
188
|
+
var errorOwner = null
|
|
189
|
+
try {
|
|
190
|
+
errorOwner = allocWord()
|
|
191
|
+
var code = raw(name, args.concat([outputOwner.pointer, errorOwner.pointer]))
|
|
192
|
+
if (code !== 0) throw errorFromHandle(code, readU32(errorOwner.pointer))
|
|
193
|
+
return readU32(outputOwner.pointer) >>> 0
|
|
194
|
+
} finally {
|
|
195
|
+
free(errorOwner)
|
|
196
|
+
free(outputOwner)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function normalizeLimits(limits) {
|
|
201
|
+
if (limits === undefined || limits === null) return null
|
|
202
|
+
if (!limits || typeof limits !== 'object' || Array.isArray(limits)) {
|
|
203
|
+
throw new TypeError('limits must be an object')
|
|
204
|
+
}
|
|
205
|
+
var normalized = {}
|
|
206
|
+
Object.keys(limits).forEach(function(name) {
|
|
207
|
+
if (!LIMIT_FIELD_SET.has(name)) {
|
|
208
|
+
throw new TypeError('unknown transform limit field: ' + name)
|
|
209
|
+
}
|
|
210
|
+
var value = limits[name]
|
|
211
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
212
|
+
throw new TranfiTransformError(
|
|
213
|
+
100, name + ' must be a positive safe integer'
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
normalized[name] = value
|
|
217
|
+
})
|
|
218
|
+
return normalized
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function safeTransformLimits(overrides) {
|
|
222
|
+
var normalized = normalizeLimits(overrides || {}) || {}
|
|
223
|
+
if (safeLimitProfile === null) {
|
|
224
|
+
var owner = alloc(184, 8)
|
|
225
|
+
try {
|
|
226
|
+
var code = raw('tf_wasm_transform_limits_init_safe_v1', [owner.pointer, 184])
|
|
227
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
228
|
+
safeLimitProfile = {}
|
|
229
|
+
for (var i = 0; i < LIMIT_FIELDS.length; i++) {
|
|
230
|
+
safeLimitProfile[LIMIT_FIELDS[i]] = readU64(owner.pointer + 8 + i * 8)
|
|
231
|
+
}
|
|
232
|
+
} finally {
|
|
233
|
+
free(owner)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return Object.assign({}, safeLimitProfile, normalized)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function limitsOwner(limits, resolved) {
|
|
240
|
+
var normalized = normalizeLimits(limits)
|
|
241
|
+
if (normalized === null) return null
|
|
242
|
+
var values = resolved || safeTransformLimits(normalized)
|
|
243
|
+
var owner = alloc(184, 8)
|
|
244
|
+
try {
|
|
245
|
+
var code = raw('tf_wasm_transform_limits_init_safe_v1', [owner.pointer, 184])
|
|
246
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
247
|
+
for (var i = 0; i < LIMIT_FIELDS.length; i++) {
|
|
248
|
+
writeU64(owner.pointer + 8 + i * 8, values[LIMIT_FIELDS[i]])
|
|
249
|
+
}
|
|
250
|
+
return owner
|
|
251
|
+
} catch (error) {
|
|
252
|
+
free(owner)
|
|
253
|
+
throw error
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function resourceLimit(message) {
|
|
258
|
+
return new TranfiTransformError(104, message)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function resolvedLimits(limits) {
|
|
262
|
+
return safeTransformLimits(limits || {})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function assertWellFormedUnicode(value, label, cancelToken, rejectNul) {
|
|
266
|
+
for (var index = 0; index < value.length; index++) {
|
|
267
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
268
|
+
var unit = value.charCodeAt(index)
|
|
269
|
+
if (rejectNul && unit === 0) {
|
|
270
|
+
throw new TypeError(label + ' must not contain NUL')
|
|
271
|
+
}
|
|
272
|
+
if (unit >= 0xd800 && unit <= 0xdbff) {
|
|
273
|
+
var next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0
|
|
274
|
+
if (next < 0xdc00 || next > 0xdfff) {
|
|
275
|
+
throw new TypeError(label + ' must not contain an unpaired UTF-16 surrogate')
|
|
276
|
+
}
|
|
277
|
+
index++
|
|
278
|
+
} else if (unit >= 0xdc00 && unit <= 0xdfff) {
|
|
279
|
+
throw new TypeError(label + ' must not contain an unpaired UTF-16 surrogate')
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
throwIfCancelled(cancelToken)
|
|
283
|
+
return value
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function utf8ByteLength(value, label, cancelToken, rejectNul, maxBytes) {
|
|
287
|
+
var bytes = 0
|
|
288
|
+
for (var index = 0; index < value.length; index++) {
|
|
289
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
290
|
+
var unit = value.charCodeAt(index)
|
|
291
|
+
if (rejectNul && unit === 0) {
|
|
292
|
+
throw new TypeError(label + ' must not contain NUL')
|
|
293
|
+
}
|
|
294
|
+
if (unit <= 0x7f) {
|
|
295
|
+
bytes += 1
|
|
296
|
+
} else if (unit <= 0x7ff) {
|
|
297
|
+
bytes += 2
|
|
298
|
+
} else if (unit >= 0xd800 && unit <= 0xdbff) {
|
|
299
|
+
var next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0
|
|
300
|
+
if (next < 0xdc00 || next > 0xdfff) {
|
|
301
|
+
throw new TypeError(label + ' must not contain an unpaired UTF-16 surrogate')
|
|
302
|
+
}
|
|
303
|
+
bytes += 4
|
|
304
|
+
index++
|
|
305
|
+
} else if (unit >= 0xdc00 && unit <= 0xdfff) {
|
|
306
|
+
throw new TypeError(label + ' must not contain an unpaired UTF-16 surrogate')
|
|
307
|
+
} else {
|
|
308
|
+
bytes += 3
|
|
309
|
+
}
|
|
310
|
+
if (maxBytes !== undefined && bytes > maxBytes) {
|
|
311
|
+
throw resourceLimit(label + ' exceeds its configured byte limit')
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
throwIfCancelled(cancelToken)
|
|
315
|
+
return bytes
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function encodeUtf8(value, label, cancelToken, maxBytes, knownLength) {
|
|
319
|
+
var total = knownLength === undefined
|
|
320
|
+
? utf8ByteLength(value, label, cancelToken, true, maxBytes)
|
|
321
|
+
: knownLength
|
|
322
|
+
var encoded = new Uint8Array(total)
|
|
323
|
+
var destination = 0
|
|
324
|
+
for (var offset = 0; offset < value.length;) {
|
|
325
|
+
throwIfCancelled(cancelToken)
|
|
326
|
+
var end = Math.min(offset + 4096, value.length)
|
|
327
|
+
if (end < value.length) {
|
|
328
|
+
var last = value.charCodeAt(end - 1)
|
|
329
|
+
if (last >= 0xd800 && last <= 0xdbff) end--
|
|
330
|
+
}
|
|
331
|
+
var chunk = value.slice(offset, end)
|
|
332
|
+
var result = encoder.encodeInto(chunk, encoded.subarray(destination))
|
|
333
|
+
if (result.read !== chunk.length) {
|
|
334
|
+
throw new Error('internal UTF-8 destination mismatch for ' + label)
|
|
335
|
+
}
|
|
336
|
+
destination += result.written
|
|
337
|
+
offset = end
|
|
338
|
+
}
|
|
339
|
+
throwIfCancelled(cancelToken)
|
|
340
|
+
if (destination !== total) {
|
|
341
|
+
throw new Error('internal UTF-8 length mismatch for ' + label)
|
|
342
|
+
}
|
|
343
|
+
return encoded
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function normalizeSchema(schema, limits, cancelToken) {
|
|
347
|
+
var fields = Array.isArray(schema)
|
|
348
|
+
? schema
|
|
349
|
+
: schema && typeof schema === 'object' && Array.isArray(schema.fields)
|
|
350
|
+
? schema.fields
|
|
351
|
+
: null
|
|
352
|
+
if (!fields || fields.length === 0) {
|
|
353
|
+
throw new TypeError('schema must be a nonempty array or { fields } object')
|
|
354
|
+
}
|
|
355
|
+
if (fields.length > limits.maxInputColumns) {
|
|
356
|
+
throw resourceLimit('prepared-transform input column limit exceeded')
|
|
357
|
+
}
|
|
358
|
+
var normalized = []
|
|
359
|
+
fields.forEach(function(field, index) {
|
|
360
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
361
|
+
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
362
|
+
throw new TypeError('schema field ' + index + ' must be an object')
|
|
363
|
+
}
|
|
364
|
+
var id = field.id
|
|
365
|
+
var name = field.name === undefined ? id : field.name
|
|
366
|
+
if (typeof id !== 'string' || !id) {
|
|
367
|
+
throw new TypeError('schema field ' + index + ' id must be a nonempty string')
|
|
368
|
+
}
|
|
369
|
+
if (typeof name !== 'string' || !name) {
|
|
370
|
+
throw new TypeError('schema field ' + index + ' name must be a nonempty string')
|
|
371
|
+
}
|
|
372
|
+
assertWellFormedUnicode(
|
|
373
|
+
id, 'schema field ' + index + ' id', cancelToken, true
|
|
374
|
+
)
|
|
375
|
+
assertWellFormedUnicode(
|
|
376
|
+
name, 'schema field ' + index + ' name', cancelToken, true
|
|
377
|
+
)
|
|
378
|
+
if (field.dtype !== 'float32' && field.dtype !== 'float64') {
|
|
379
|
+
throw new TypeError('schema field ' + index + ' dtype must be float32 or float64')
|
|
380
|
+
}
|
|
381
|
+
normalized.push({ id: id, name: name, dtype: field.dtype })
|
|
382
|
+
})
|
|
383
|
+
throwIfCancelled(cancelToken)
|
|
384
|
+
return normalized
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function schemaOwner(schema, limits, cancelToken) {
|
|
388
|
+
var fields = normalizeSchema(schema, limits, cancelToken)
|
|
389
|
+
var descriptorBytes = fields.length * 32
|
|
390
|
+
if (descriptorBytes > limits.maxAllocationBytes) {
|
|
391
|
+
throw resourceLimit('prepared-transform schema allocation limit exceeded')
|
|
392
|
+
}
|
|
393
|
+
var decodedBytes = 0
|
|
394
|
+
var preparedFields = fields.map(function(field, index) {
|
|
395
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
396
|
+
var maxEncodedBytes = Math.min(
|
|
397
|
+
limits.maxStringBytes, limits.maxAllocationBytes - 1
|
|
398
|
+
)
|
|
399
|
+
var idLength = utf8ByteLength(
|
|
400
|
+
field.id, 'schema field ' + index + ' id', cancelToken, true,
|
|
401
|
+
maxEncodedBytes
|
|
402
|
+
)
|
|
403
|
+
var nameLength = utf8ByteLength(
|
|
404
|
+
field.name, 'schema field ' + index + ' name', cancelToken, true,
|
|
405
|
+
maxEncodedBytes
|
|
406
|
+
)
|
|
407
|
+
if (decodedBytes + idLength + nameLength > limits.maxDecodedStringBytes) {
|
|
408
|
+
throw resourceLimit('prepared-transform decoded string limit exceeded')
|
|
409
|
+
}
|
|
410
|
+
decodedBytes += idLength + nameLength
|
|
411
|
+
return { field: field, idLength: idLength, nameLength: nameLength }
|
|
412
|
+
})
|
|
413
|
+
throwIfCancelled(cancelToken)
|
|
414
|
+
var encodedFields = preparedFields.map(function(prepared, index) {
|
|
415
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
416
|
+
var field = prepared.field
|
|
417
|
+
var maxEncodedBytes = Math.min(
|
|
418
|
+
limits.maxStringBytes, limits.maxAllocationBytes - 1
|
|
419
|
+
)
|
|
420
|
+
return {
|
|
421
|
+
field: field,
|
|
422
|
+
id: encodeUtf8(
|
|
423
|
+
field.id, 'schema field ' + index + ' id', cancelToken,
|
|
424
|
+
maxEncodedBytes, prepared.idLength
|
|
425
|
+
),
|
|
426
|
+
name: encodeUtf8(
|
|
427
|
+
field.name, 'schema field ' + index + ' name', cancelToken,
|
|
428
|
+
maxEncodedBytes, prepared.nameLength
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
var allocations = []
|
|
433
|
+
var dtypes = []
|
|
434
|
+
var fieldOwner = null
|
|
435
|
+
var schemaAllocation = null
|
|
436
|
+
try {
|
|
437
|
+
fieldOwner = alloc(descriptorBytes, 4)
|
|
438
|
+
allocations.push(fieldOwner)
|
|
439
|
+
schemaAllocation = alloc(20, 4)
|
|
440
|
+
allocations.push(schemaAllocation)
|
|
441
|
+
encodedFields.forEach(function(encoded, index) {
|
|
442
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
443
|
+
var field = encoded.field
|
|
444
|
+
var idOwner = allocBytes(encoded.id, 1, cancelToken)
|
|
445
|
+
allocations.push(idOwner)
|
|
446
|
+
var nameOwner = allocBytes(encoded.name, 1, cancelToken)
|
|
447
|
+
allocations.push(nameOwner)
|
|
448
|
+
var offset = fieldOwner.pointer + index * 32
|
|
449
|
+
writeU32(offset, 1)
|
|
450
|
+
writeU32(offset + 4, 32)
|
|
451
|
+
writeU32(offset + 8, field.dtype === 'float32' ? VIEW_FLOAT32 : VIEW_FLOAT64)
|
|
452
|
+
writeU32(offset + 12, 0)
|
|
453
|
+
writeU32(offset + 16, idOwner.pointer)
|
|
454
|
+
writeU32(offset + 20, idOwner.size)
|
|
455
|
+
writeU32(offset + 24, nameOwner.pointer)
|
|
456
|
+
writeU32(offset + 28, nameOwner.size)
|
|
457
|
+
dtypes.push(field.dtype)
|
|
458
|
+
})
|
|
459
|
+
writeU32(schemaAllocation.pointer, 1)
|
|
460
|
+
writeU32(schemaAllocation.pointer + 4, 20)
|
|
461
|
+
writeU32(schemaAllocation.pointer + 8, fields.length)
|
|
462
|
+
writeU32(schemaAllocation.pointer + 12, fieldOwner.pointer)
|
|
463
|
+
writeU32(schemaAllocation.pointer + 16, descriptorBytes)
|
|
464
|
+
return {
|
|
465
|
+
pointer: schemaAllocation.pointer,
|
|
466
|
+
dtypes: dtypes,
|
|
467
|
+
free: function() { allocations.reverse().forEach(free) }
|
|
468
|
+
}
|
|
469
|
+
} catch (error) {
|
|
470
|
+
allocations.reverse().forEach(free)
|
|
471
|
+
throw error
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function tableOwner(table, dtypes, limits, phase, cancelToken) {
|
|
476
|
+
throwIfCancelled(cancelToken)
|
|
477
|
+
if (!table || typeof table !== 'object' || Array.isArray(table)) {
|
|
478
|
+
throw new TypeError('table must be an object with rows and columns')
|
|
479
|
+
}
|
|
480
|
+
var rows = table.rows
|
|
481
|
+
var columns = table.columns
|
|
482
|
+
if (!Number.isInteger(rows) || rows < 0 || rows > 0xffffffff) {
|
|
483
|
+
throw new TypeError('table.rows must be a nonnegative uint32 integer')
|
|
484
|
+
}
|
|
485
|
+
if (!Array.isArray(columns) || columns.length !== dtypes.length) {
|
|
486
|
+
throw new TypeError('table column count does not match the prepared schema')
|
|
487
|
+
}
|
|
488
|
+
var maxRows = phase === 'analyze'
|
|
489
|
+
? limits.maxAnalyzerRows
|
|
490
|
+
: limits.maxApplyRows
|
|
491
|
+
var maxInputBytes = phase === 'analyze'
|
|
492
|
+
? limits.maxAnalyzerInputBytes
|
|
493
|
+
: limits.maxApplyInputBytes
|
|
494
|
+
if (rows > maxRows) {
|
|
495
|
+
throw resourceLimit('prepared-transform row limit exceeded')
|
|
496
|
+
}
|
|
497
|
+
var descriptorBytes = columns.length * 36
|
|
498
|
+
if (descriptorBytes > limits.maxAllocationBytes) {
|
|
499
|
+
throw resourceLimit('prepared-transform table allocation limit exceeded')
|
|
500
|
+
}
|
|
501
|
+
var totalInputBytes = 0n
|
|
502
|
+
var prepared = columns.map(function(value, index) {
|
|
503
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
504
|
+
var config = ArrayBuffer.isView(value) ? { data: value } : value
|
|
505
|
+
if (!config || typeof config !== 'object' || !ArrayBuffer.isView(config.data)) {
|
|
506
|
+
throw new TypeError('table column ' + index + ' data must be a typed array')
|
|
507
|
+
}
|
|
508
|
+
var expected = dtypes[index]
|
|
509
|
+
var ArrayType = expected === 'float32' ? Float32Array : Float64Array
|
|
510
|
+
if (!(config.data instanceof ArrayType)) {
|
|
511
|
+
throw new TypeError('table column ' + index + ' dtype mismatches schema')
|
|
512
|
+
}
|
|
513
|
+
if (rows === 0 && (config.data.byteLength !== 0
|
|
514
|
+
|| config.validity !== undefined && config.validity !== null
|
|
515
|
+
|| config.validityBitOffset !== undefined
|
|
516
|
+
|| config.validityBitStride !== undefined)) {
|
|
517
|
+
throw new TranfiTransformError(
|
|
518
|
+
100, 'zero-row column must carry empty data and no validity span'
|
|
519
|
+
)
|
|
520
|
+
}
|
|
521
|
+
var itemSize = expected === 'float32' ? 4 : 8
|
|
522
|
+
var stride = config.strideBytes === undefined ? itemSize : config.strideBytes
|
|
523
|
+
if (!Number.isInteger(stride) || stride <= 0 || stride > 0xffffffff) {
|
|
524
|
+
throw new TypeError('table column ' + index + ' strideBytes must be positive')
|
|
525
|
+
}
|
|
526
|
+
var requiredData = rows === 0
|
|
527
|
+
? 0n
|
|
528
|
+
: BigInt(rows - 1) * BigInt(stride) + BigInt(itemSize)
|
|
529
|
+
if (requiredData > BigInt(config.data.byteLength)) {
|
|
530
|
+
throw new TypeError('table column ' + index + ' data buffer is too small')
|
|
531
|
+
}
|
|
532
|
+
if (requiredData > 0xffffffffn
|
|
533
|
+
|| requiredData > BigInt(limits.maxAllocationBytes)) {
|
|
534
|
+
throw resourceLimit('prepared-transform input allocation limit exceeded')
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
var bitOffset = 0
|
|
538
|
+
var bitStride = 0
|
|
539
|
+
var requiredValidity = 0n
|
|
540
|
+
if (config.validity !== undefined && config.validity !== null) {
|
|
541
|
+
if (!(config.validity instanceof Uint8Array)) {
|
|
542
|
+
throw new TypeError('table column ' + index + ' validity must be Uint8Array')
|
|
543
|
+
}
|
|
544
|
+
bitOffset = config.validityBitOffset === undefined ? 0 : config.validityBitOffset
|
|
545
|
+
bitStride = config.validityBitStride === undefined ? 1 : config.validityBitStride
|
|
546
|
+
if (!Number.isInteger(bitOffset) || bitOffset < 0 || bitOffset > 0xffffffff
|
|
547
|
+
|| !Number.isInteger(bitStride) || bitStride <= 0 || bitStride > 0xffffffff) {
|
|
548
|
+
throw new TypeError('table column ' + index + ' validity bit metadata is invalid')
|
|
549
|
+
}
|
|
550
|
+
var requiredBits = rows === 0
|
|
551
|
+
? 0n
|
|
552
|
+
: BigInt(bitOffset) + BigInt(rows - 1) * BigInt(bitStride) + 1n
|
|
553
|
+
requiredValidity = (requiredBits + 7n) / 8n
|
|
554
|
+
if (requiredValidity > BigInt(config.validity.byteLength)) {
|
|
555
|
+
throw new TypeError('table column ' + index + ' validity buffer is too small')
|
|
556
|
+
}
|
|
557
|
+
if (requiredValidity > 0xffffffffn
|
|
558
|
+
|| requiredValidity > BigInt(limits.maxAllocationBytes)) {
|
|
559
|
+
throw resourceLimit('prepared-transform validity allocation limit exceeded')
|
|
560
|
+
}
|
|
561
|
+
} else if (config.validityBitOffset !== undefined
|
|
562
|
+
|| config.validityBitStride !== undefined) {
|
|
563
|
+
throw new TypeError('validity bit metadata requires a validity bitmap')
|
|
564
|
+
}
|
|
565
|
+
totalInputBytes += requiredData + requiredValidity
|
|
566
|
+
if (totalInputBytes > BigInt(maxInputBytes)) {
|
|
567
|
+
throw resourceLimit('prepared-transform input byte limit exceeded')
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
config: config,
|
|
571
|
+
itemSize: itemSize,
|
|
572
|
+
stride: stride,
|
|
573
|
+
dataBytes: Number(requiredData),
|
|
574
|
+
validityBytes: Number(requiredValidity),
|
|
575
|
+
bitOffset: bitOffset,
|
|
576
|
+
bitStride: bitStride
|
|
577
|
+
}
|
|
578
|
+
})
|
|
579
|
+
var allocations = []
|
|
580
|
+
var columnsOwner = null
|
|
581
|
+
var tableAllocation = null
|
|
582
|
+
try {
|
|
583
|
+
columnsOwner = alloc(descriptorBytes, 4)
|
|
584
|
+
allocations.push(columnsOwner)
|
|
585
|
+
tableAllocation = alloc(24, 4)
|
|
586
|
+
allocations.push(tableAllocation)
|
|
587
|
+
prepared.forEach(function(input, index) {
|
|
588
|
+
if (index % 4096 === 0) throwIfCancelled(cancelToken)
|
|
589
|
+
var config = input.config
|
|
590
|
+
var bytes = new Uint8Array(
|
|
591
|
+
config.data.buffer, config.data.byteOffset, input.dataBytes
|
|
592
|
+
)
|
|
593
|
+
var dataOwner = bytes.byteLength
|
|
594
|
+
? allocBytes(bytes, input.itemSize, cancelToken) : null
|
|
595
|
+
if (dataOwner) allocations.push(dataOwner)
|
|
596
|
+
var validityOwner = null
|
|
597
|
+
if (input.validityBytes) {
|
|
598
|
+
validityOwner = input.validityBytes
|
|
599
|
+
? allocBytes(new Uint8Array(
|
|
600
|
+
config.validity.buffer,
|
|
601
|
+
config.validity.byteOffset,
|
|
602
|
+
input.validityBytes
|
|
603
|
+
), 1, cancelToken)
|
|
604
|
+
: null
|
|
605
|
+
if (validityOwner) allocations.push(validityOwner)
|
|
606
|
+
}
|
|
607
|
+
var offset = columnsOwner.pointer + index * 36
|
|
608
|
+
writeU32(offset, 1)
|
|
609
|
+
writeU32(offset + 4, 36)
|
|
610
|
+
writeU32(offset + 8, dataOwner ? dataOwner.pointer : 0)
|
|
611
|
+
writeU32(offset + 12, input.dataBytes)
|
|
612
|
+
writeU32(offset + 16, input.stride)
|
|
613
|
+
writeU32(offset + 20, validityOwner ? validityOwner.pointer : 0)
|
|
614
|
+
writeU32(offset + 24, input.validityBytes)
|
|
615
|
+
writeU32(offset + 28, input.bitOffset)
|
|
616
|
+
writeU32(offset + 32, input.bitStride)
|
|
617
|
+
})
|
|
618
|
+
writeU32(tableAllocation.pointer, 1)
|
|
619
|
+
writeU32(tableAllocation.pointer + 4, 24)
|
|
620
|
+
writeU32(tableAllocation.pointer + 8, rows)
|
|
621
|
+
writeU32(tableAllocation.pointer + 12, columns.length)
|
|
622
|
+
writeU32(tableAllocation.pointer + 16, columnsOwner.pointer)
|
|
623
|
+
writeU32(tableAllocation.pointer + 20, descriptorBytes)
|
|
624
|
+
return {
|
|
625
|
+
pointer: tableAllocation.pointer,
|
|
626
|
+
free: function() { allocations.reverse().forEach(free) }
|
|
627
|
+
}
|
|
628
|
+
} catch (error) {
|
|
629
|
+
allocations.reverse().forEach(free)
|
|
630
|
+
throw error
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function bytesFromHandle(handle) {
|
|
635
|
+
var sizeOwner = null
|
|
636
|
+
var dataOwner = null
|
|
637
|
+
try {
|
|
638
|
+
sizeOwner = allocWord()
|
|
639
|
+
var code = raw('tf_wasm_transform_owned_bytes_size', [handle, sizeOwner.pointer])
|
|
640
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
641
|
+
var length = readU32(sizeOwner.pointer)
|
|
642
|
+
dataOwner = alloc(length, 1)
|
|
643
|
+
code = raw('tf_wasm_transform_owned_bytes_copy', [
|
|
644
|
+
handle, dataOwner.pointer, length
|
|
645
|
+
])
|
|
646
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
647
|
+
return wasm.HEAPU8.slice(dataOwner.pointer, dataOwner.pointer + length)
|
|
648
|
+
} finally {
|
|
649
|
+
free(dataOwner)
|
|
650
|
+
free(sizeOwner)
|
|
651
|
+
destroyHandle(handle)
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function denseFromHandle(handle, cancelToken) {
|
|
656
|
+
var infoOwner = null
|
|
657
|
+
var dataOwner = null
|
|
658
|
+
try {
|
|
659
|
+
infoOwner = alloc(28, 4)
|
|
660
|
+
var code = raw('tf_wasm_transform_owned_dense_info', [handle, infoOwner.pointer])
|
|
661
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
662
|
+
var dtype = readU32(infoOwner.pointer + 8)
|
|
663
|
+
var rows = readU32(infoOwner.pointer + 16)
|
|
664
|
+
var columns = readU32(infoOwner.pointer + 20)
|
|
665
|
+
var byteLength = readU32(infoOwner.pointer + 24)
|
|
666
|
+
if (dtype !== VIEW_FLOAT64 || byteLength % 8 !== 0
|
|
667
|
+
|| BigInt(rows) * BigInt(columns) * 8n !== BigInt(byteLength)) {
|
|
668
|
+
throw new TranfiTransformError(199, 'invalid dense output from WASM')
|
|
669
|
+
}
|
|
670
|
+
throwIfCancelled(cancelToken)
|
|
671
|
+
dataOwner = alloc(byteLength, 8)
|
|
672
|
+
code = raw('tf_wasm_transform_owned_dense_copy', [
|
|
673
|
+
handle, dataOwner.pointer, byteLength
|
|
674
|
+
])
|
|
675
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
676
|
+
throwIfCancelled(cancelToken)
|
|
677
|
+
var result = new Float64Array(byteLength / 8)
|
|
678
|
+
var view = dataView()
|
|
679
|
+
for (var i = 0; i < result.length; i++) {
|
|
680
|
+
if (i % 8192 === 0) throwIfCancelled(cancelToken)
|
|
681
|
+
result[i] = view.getFloat64(dataOwner.pointer + i * 8, true)
|
|
682
|
+
}
|
|
683
|
+
throwIfCancelled(cancelToken)
|
|
684
|
+
return { rows: rows, columns: columns, data: result }
|
|
685
|
+
} finally {
|
|
686
|
+
free(dataOwner)
|
|
687
|
+
free(infoOwner)
|
|
688
|
+
destroyHandle(handle)
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function normalizeRecipeJSON(recipe, limits) {
|
|
693
|
+
if (typeof recipe === 'string') {
|
|
694
|
+
var stringLimit = Math.min(
|
|
695
|
+
limits.maxRecipeBytes, limits.maxAllocationBytes - 1
|
|
696
|
+
)
|
|
697
|
+
var stringLength = utf8ByteLength(
|
|
698
|
+
recipe, 'recipe', null, false, stringLimit
|
|
699
|
+
)
|
|
700
|
+
return encodeUtf8(recipe, 'recipe', null, stringLimit, stringLength)
|
|
701
|
+
}
|
|
702
|
+
if (recipe instanceof Uint8Array) {
|
|
703
|
+
if (recipe.byteLength > limits.maxRecipeBytes
|
|
704
|
+
|| recipe.byteLength > limits.maxAllocationBytes) {
|
|
705
|
+
throw resourceLimit('prepared-transform recipe byte limit exceeded')
|
|
706
|
+
}
|
|
707
|
+
return new Uint8Array(recipe.buffer, recipe.byteOffset, recipe.byteLength)
|
|
708
|
+
}
|
|
709
|
+
if (!recipe || typeof recipe !== 'object' || Array.isArray(recipe)) {
|
|
710
|
+
throw new TypeError('recipe must be an object, string, or Uint8Array')
|
|
711
|
+
}
|
|
712
|
+
var text = stringifyRecipe(recipe, limits)
|
|
713
|
+
var textLimit = Math.min(
|
|
714
|
+
limits.maxRecipeBytes, limits.maxAllocationBytes - 1
|
|
715
|
+
)
|
|
716
|
+
var textLength = utf8ByteLength(
|
|
717
|
+
text, 'recipe', null, false, textLimit
|
|
718
|
+
)
|
|
719
|
+
return encodeUtf8(text, 'recipe', null, textLimit, textLength)
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function runtimeOptions(options) {
|
|
723
|
+
if (options === undefined) options = {}
|
|
724
|
+
if (typeof options !== 'object' || Array.isArray(options)) {
|
|
725
|
+
throw new TypeError('transform runtime options must be an object')
|
|
726
|
+
}
|
|
727
|
+
Object.keys(options).forEach(function(name) {
|
|
728
|
+
if (['limits', 'cancelToken', 'hostPolicy', 'spillDir'].indexOf(name) < 0) {
|
|
729
|
+
throw new TypeError('unknown transform runtime option: ' + name)
|
|
730
|
+
}
|
|
731
|
+
})
|
|
732
|
+
if (options.hostPolicy !== undefined && options.hostPolicy !== null) {
|
|
733
|
+
throw new TranfiTransformError(
|
|
734
|
+
113, 'prepared-transform hostPolicy is reserved but not implemented'
|
|
735
|
+
)
|
|
736
|
+
}
|
|
737
|
+
if (options.spillDir !== undefined && options.spillDir !== null
|
|
738
|
+
&& options.spillDir !== '') {
|
|
739
|
+
throw new TranfiTransformError(
|
|
740
|
+
113, 'prepared-transform spillDir is reserved but not implemented'
|
|
741
|
+
)
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
limits: options.limits,
|
|
745
|
+
cancelToken: options.cancelToken || null
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function throwIfCancelled(token) {
|
|
750
|
+
if (token && token._isRequested()) {
|
|
751
|
+
throw new TranfiTransformError(109, ERROR_NAMES[109])
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function tokenHandle(token) {
|
|
756
|
+
if (token === null) return 0
|
|
757
|
+
if (!(token instanceof TransformCancelToken)) {
|
|
758
|
+
throw new TypeError('cancelToken must be a TransformCancelToken')
|
|
759
|
+
}
|
|
760
|
+
return token._requireOpen()
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
class OwnedTransform {
|
|
764
|
+
constructor(handle, token) {
|
|
765
|
+
this._handle = handle >>> 0
|
|
766
|
+
this._token = token || null
|
|
767
|
+
if (this._token) this._token._retain()
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
_requireOpen() {
|
|
771
|
+
if (!this._handle) {
|
|
772
|
+
throw new TranfiTransformError(112, 'prepared transform object is closed')
|
|
773
|
+
}
|
|
774
|
+
return this._handle
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
close() {
|
|
778
|
+
if (this._handle) {
|
|
779
|
+
var code = destroyHandle(this._handle)
|
|
780
|
+
this._handle = 0
|
|
781
|
+
if (this._token) {
|
|
782
|
+
this._token._release()
|
|
783
|
+
this._token = null
|
|
784
|
+
}
|
|
785
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
dispose() {
|
|
790
|
+
this.close()
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
class TransformCancelToken extends OwnedTransform {
|
|
795
|
+
constructor(handle, sharedFlag, hostSlot) {
|
|
796
|
+
super(handle, null)
|
|
797
|
+
this._sharedFlag = sharedFlag || null
|
|
798
|
+
this._hostSlot = hostSlot
|
|
799
|
+
this._references = 1
|
|
800
|
+
this._requested = false
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
_retain() {
|
|
804
|
+
this._requireOpen()
|
|
805
|
+
++this._references
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
_release() {
|
|
809
|
+
--this._references
|
|
810
|
+
if (this._references === 0 && this._hostSlot !== NO_HOST_CANCEL) {
|
|
811
|
+
cancelPolls.delete(this._hostSlot)
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
request() {
|
|
816
|
+
var handle = this._requireOpen()
|
|
817
|
+
this._requested = true
|
|
818
|
+
if (this._sharedFlag) Atomics.store(this._sharedFlag, 0, 1)
|
|
819
|
+
var code = raw('tf_wasm_transform_cancel_request', [handle])
|
|
820
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
_observeNextPoll(observer) {
|
|
824
|
+
this._requireOpen()
|
|
825
|
+
if (typeof observer !== 'function') return
|
|
826
|
+
var poll = cancelPolls.get(this._hostSlot)
|
|
827
|
+
if (poll) poll.observer = observer
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
get requested() {
|
|
831
|
+
this._requireOpen()
|
|
832
|
+
return this._isRequested()
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
_isRequested() {
|
|
836
|
+
return this._requested || Boolean(
|
|
837
|
+
this._sharedFlag && Atomics.load(this._sharedFlag, 0) !== 0
|
|
838
|
+
)
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
close() {
|
|
842
|
+
if (this._handle) {
|
|
843
|
+
var code = destroyHandle(this._handle)
|
|
844
|
+
this._handle = 0
|
|
845
|
+
this._release()
|
|
846
|
+
if (code !== 0) throw new TranfiTransformError(code, ERROR_NAMES[code])
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function createTransformCancelToken(options) {
|
|
852
|
+
options = options || {}
|
|
853
|
+
var flag = options.sharedFlag || null
|
|
854
|
+
var slot = NO_HOST_CANCEL
|
|
855
|
+
if (flag !== null) {
|
|
856
|
+
var shared = typeof SharedArrayBuffer !== 'undefined'
|
|
857
|
+
&& flag instanceof Int32Array
|
|
858
|
+
&& Object.prototype.toString.call(flag.buffer) === '[object SharedArrayBuffer]'
|
|
859
|
+
if (!shared || flag.length < 1 || typeof Atomics === 'undefined') {
|
|
860
|
+
throw new TypeError('sharedFlag must be a nonempty SharedArrayBuffer-backed Int32Array')
|
|
861
|
+
}
|
|
862
|
+
do {
|
|
863
|
+
slot = nextCancelSlot++ >>> 0
|
|
864
|
+
if (nextCancelSlot === NO_HOST_CANCEL) nextCancelSlot = 1
|
|
865
|
+
} while (cancelPolls.has(slot))
|
|
866
|
+
cancelPolls.set(slot, { flag: flag, observer: null })
|
|
867
|
+
}
|
|
868
|
+
var limits = null
|
|
869
|
+
try {
|
|
870
|
+
var effectiveLimits = resolvedLimits(options.limits)
|
|
871
|
+
limits = limitsOwner(options.limits, effectiveLimits)
|
|
872
|
+
var handle = callForHandle('tf_wasm_transform_cancel_create', [
|
|
873
|
+
slot, limits ? limits.pointer : 0
|
|
874
|
+
])
|
|
875
|
+
return new TransformCancelToken(handle, flag, slot)
|
|
876
|
+
} catch (error) {
|
|
877
|
+
if (slot !== NO_HOST_CANCEL) cancelPolls.delete(slot)
|
|
878
|
+
throw error
|
|
879
|
+
} finally {
|
|
880
|
+
free(limits)
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
class TransformRecipe extends OwnedTransform {
|
|
885
|
+
static fromJSON(recipe, options) {
|
|
886
|
+
options = options || {}
|
|
887
|
+
var bytes = null
|
|
888
|
+
var limits = null
|
|
889
|
+
try {
|
|
890
|
+
var effectiveLimits = resolvedLimits(options.limits)
|
|
891
|
+
var normalized = normalizeRecipeJSON(recipe, effectiveLimits)
|
|
892
|
+
limits = limitsOwner(options.limits, effectiveLimits)
|
|
893
|
+
bytes = allocBytes(normalized, 1)
|
|
894
|
+
var handle = callForHandle('tf_wasm_transform_recipe_from_json', [
|
|
895
|
+
bytes.pointer, bytes.size, limits ? limits.pointer : 0
|
|
896
|
+
])
|
|
897
|
+
return new TransformRecipe(handle)
|
|
898
|
+
} finally {
|
|
899
|
+
free(limits)
|
|
900
|
+
free(bytes)
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
analyzer(schema, options) {
|
|
905
|
+
var runtime = runtimeOptions(options)
|
|
906
|
+
var schemaAllocation = null
|
|
907
|
+
var limits = null
|
|
908
|
+
try {
|
|
909
|
+
var effectiveLimits = resolvedLimits(runtime.limits)
|
|
910
|
+
var cancelHandle = tokenHandle(runtime.cancelToken)
|
|
911
|
+
throwIfCancelled(runtime.cancelToken)
|
|
912
|
+
schemaAllocation = schemaOwner(
|
|
913
|
+
schema, effectiveLimits, runtime.cancelToken
|
|
914
|
+
)
|
|
915
|
+
throwIfCancelled(runtime.cancelToken)
|
|
916
|
+
limits = limitsOwner(runtime.limits, effectiveLimits)
|
|
917
|
+
var handle = callForHandle('tf_wasm_transform_analyzer_create', [
|
|
918
|
+
this._requireOpen(), schemaAllocation.pointer,
|
|
919
|
+
limits ? limits.pointer : 0, cancelHandle
|
|
920
|
+
])
|
|
921
|
+
return new TransformAnalyzer(
|
|
922
|
+
handle, schemaAllocation.dtypes, runtime.cancelToken, effectiveLimits
|
|
923
|
+
)
|
|
924
|
+
} finally {
|
|
925
|
+
free(limits)
|
|
926
|
+
if (schemaAllocation) schemaAllocation.free()
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
class TransformAnalyzer extends OwnedTransform {
|
|
932
|
+
constructor(handle, dtypes, token, limits) {
|
|
933
|
+
super(handle, token)
|
|
934
|
+
this._dtypes = dtypes.slice()
|
|
935
|
+
this._limits = limits
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
push(table) {
|
|
939
|
+
try {
|
|
940
|
+
throwIfCancelled(this._token)
|
|
941
|
+
} catch (error) {
|
|
942
|
+
this.close()
|
|
943
|
+
throw error
|
|
944
|
+
}
|
|
945
|
+
var tableAllocation
|
|
946
|
+
try {
|
|
947
|
+
tableAllocation = tableOwner(
|
|
948
|
+
table, this._dtypes, this._limits, 'analyze', this._token
|
|
949
|
+
)
|
|
950
|
+
} catch (error) {
|
|
951
|
+
if (error && error.code === 109) this.close()
|
|
952
|
+
throw error
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
try {
|
|
956
|
+
throwIfCancelled(this._token)
|
|
957
|
+
} catch (error) {
|
|
958
|
+
this.close()
|
|
959
|
+
throw error
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
callWithError('tf_wasm_transform_analyzer_push', [
|
|
963
|
+
this._requireOpen(), tableAllocation.pointer
|
|
964
|
+
])
|
|
965
|
+
} catch (error) {
|
|
966
|
+
if (error && error.code === 109) this.close()
|
|
967
|
+
throw error
|
|
968
|
+
}
|
|
969
|
+
return this
|
|
970
|
+
} finally {
|
|
971
|
+
tableAllocation.free()
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
finalize() {
|
|
976
|
+
try {
|
|
977
|
+
return new TransformPlan(callForHandle(
|
|
978
|
+
'tf_wasm_transform_analyzer_finalize', [this._requireOpen()]
|
|
979
|
+
))
|
|
980
|
+
} catch (error) {
|
|
981
|
+
if (error && error.code === 109) this.close()
|
|
982
|
+
throw error
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
class TransformPlan extends OwnedTransform {
|
|
988
|
+
static fromBytes(bytes, options) {
|
|
989
|
+
options = options || {}
|
|
990
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
991
|
+
throw new TypeError('plan bytes must be Uint8Array')
|
|
992
|
+
}
|
|
993
|
+
var input = null
|
|
994
|
+
var runtime = runtimeOptions(options)
|
|
995
|
+
var limits = null
|
|
996
|
+
try {
|
|
997
|
+
var effectiveLimits = resolvedLimits(runtime.limits)
|
|
998
|
+
if (bytes.byteLength > effectiveLimits.maxPlanBytes
|
|
999
|
+
|| bytes.byteLength > effectiveLimits.maxAllocationBytes) {
|
|
1000
|
+
throw resourceLimit('prepared-transform plan byte limit exceeded')
|
|
1001
|
+
}
|
|
1002
|
+
throwIfCancelled(runtime.cancelToken)
|
|
1003
|
+
limits = limitsOwner(runtime.limits, effectiveLimits)
|
|
1004
|
+
input = allocBytes(new Uint8Array(
|
|
1005
|
+
bytes.buffer, bytes.byteOffset, bytes.byteLength
|
|
1006
|
+
), 1, runtime.cancelToken)
|
|
1007
|
+
throwIfCancelled(runtime.cancelToken)
|
|
1008
|
+
var handle = callForHandle('tf_wasm_transform_plan_import', [
|
|
1009
|
+
input.pointer, input.size, limits ? limits.pointer : 0,
|
|
1010
|
+
tokenHandle(runtime.cancelToken)
|
|
1011
|
+
])
|
|
1012
|
+
return new TransformPlan(handle)
|
|
1013
|
+
} finally {
|
|
1014
|
+
free(limits)
|
|
1015
|
+
free(input)
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
toBytes(options) {
|
|
1020
|
+
options = options || {}
|
|
1021
|
+
var limits = limitsOwner(options.limits)
|
|
1022
|
+
try {
|
|
1023
|
+
return bytesFromHandle(callForHandle('tf_wasm_transform_plan_export', [
|
|
1024
|
+
this._requireOpen(), limits ? limits.pointer : 0
|
|
1025
|
+
]))
|
|
1026
|
+
} finally {
|
|
1027
|
+
free(limits)
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
schemaJSON(which, options) {
|
|
1032
|
+
which = which === undefined ? 'output' : which
|
|
1033
|
+
options = options || {}
|
|
1034
|
+
var selector = which === 'input'
|
|
1035
|
+
? SCHEMA_INPUT
|
|
1036
|
+
: which === 'output'
|
|
1037
|
+
? SCHEMA_OUTPUT
|
|
1038
|
+
: 0
|
|
1039
|
+
if (!selector) throw new TypeError("which must be 'input' or 'output'")
|
|
1040
|
+
var limits = limitsOwner(options.limits)
|
|
1041
|
+
try {
|
|
1042
|
+
return bytesFromHandle(callForHandle('tf_wasm_transform_plan_schema_json', [
|
|
1043
|
+
this._requireOpen(), selector, limits ? limits.pointer : 0
|
|
1044
|
+
]))
|
|
1045
|
+
} finally {
|
|
1046
|
+
free(limits)
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
recipeSha256(options) {
|
|
1051
|
+
options = options || {}
|
|
1052
|
+
var limits = limitsOwner(options.limits)
|
|
1053
|
+
try {
|
|
1054
|
+
return decoder.decode(bytesFromHandle(callForHandle(
|
|
1055
|
+
'tf_wasm_transform_plan_recipe_sha256', [
|
|
1056
|
+
this._requireOpen(), limits ? limits.pointer : 0
|
|
1057
|
+
]
|
|
1058
|
+
)))
|
|
1059
|
+
} finally {
|
|
1060
|
+
free(limits)
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
apply(schema, options) {
|
|
1065
|
+
var runtime = runtimeOptions(options)
|
|
1066
|
+
var schemaAllocation = null
|
|
1067
|
+
var limits = null
|
|
1068
|
+
try {
|
|
1069
|
+
var effectiveLimits = resolvedLimits(runtime.limits)
|
|
1070
|
+
var cancelHandle = tokenHandle(runtime.cancelToken)
|
|
1071
|
+
throwIfCancelled(runtime.cancelToken)
|
|
1072
|
+
schemaAllocation = schemaOwner(
|
|
1073
|
+
schema, effectiveLimits, runtime.cancelToken
|
|
1074
|
+
)
|
|
1075
|
+
throwIfCancelled(runtime.cancelToken)
|
|
1076
|
+
limits = limitsOwner(runtime.limits, effectiveLimits)
|
|
1077
|
+
var handle = callForHandle('tf_wasm_transform_apply_create', [
|
|
1078
|
+
this._requireOpen(), schemaAllocation.pointer,
|
|
1079
|
+
limits ? limits.pointer : 0, cancelHandle
|
|
1080
|
+
])
|
|
1081
|
+
return new TransformApply(
|
|
1082
|
+
handle, schemaAllocation.dtypes, runtime.cancelToken, effectiveLimits
|
|
1083
|
+
)
|
|
1084
|
+
} finally {
|
|
1085
|
+
free(limits)
|
|
1086
|
+
if (schemaAllocation) schemaAllocation.free()
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
class TransformApply extends OwnedTransform {
|
|
1092
|
+
constructor(handle, dtypes, token, limits) {
|
|
1093
|
+
super(handle, token)
|
|
1094
|
+
this._dtypes = dtypes.slice()
|
|
1095
|
+
this._limits = limits
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
run(table) {
|
|
1099
|
+
try {
|
|
1100
|
+
throwIfCancelled(this._token)
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
this.close()
|
|
1103
|
+
throw error
|
|
1104
|
+
}
|
|
1105
|
+
var tableAllocation
|
|
1106
|
+
try {
|
|
1107
|
+
tableAllocation = tableOwner(
|
|
1108
|
+
table, this._dtypes, this._limits, 'apply', this._token
|
|
1109
|
+
)
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
if (error && error.code === 109) this.close()
|
|
1112
|
+
throw error
|
|
1113
|
+
}
|
|
1114
|
+
try {
|
|
1115
|
+
try {
|
|
1116
|
+
throwIfCancelled(this._token)
|
|
1117
|
+
} catch (error) {
|
|
1118
|
+
this.close()
|
|
1119
|
+
throw error
|
|
1120
|
+
}
|
|
1121
|
+
var denseHandle
|
|
1122
|
+
try {
|
|
1123
|
+
denseHandle = callForHandle('tf_wasm_transform_apply_run', [
|
|
1124
|
+
this._requireOpen(), tableAllocation.pointer
|
|
1125
|
+
])
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
if (error && error.code === 109) this.close()
|
|
1128
|
+
throw error
|
|
1129
|
+
}
|
|
1130
|
+
try {
|
|
1131
|
+
return denseFromHandle(denseHandle, this._token)
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
try {
|
|
1134
|
+
this.close()
|
|
1135
|
+
} catch (_) {}
|
|
1136
|
+
throw error
|
|
1137
|
+
}
|
|
1138
|
+
} finally {
|
|
1139
|
+
tableAllocation.free()
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
return {
|
|
1145
|
+
TranfiTransformError: TranfiTransformError,
|
|
1146
|
+
TransformRecipe: TransformRecipe,
|
|
1147
|
+
TransformAnalyzer: TransformAnalyzer,
|
|
1148
|
+
TransformPlan: TransformPlan,
|
|
1149
|
+
TransformApply: TransformApply,
|
|
1150
|
+
TransformCancelToken: TransformCancelToken,
|
|
1151
|
+
createTransformCancelToken: createTransformCancelToken,
|
|
1152
|
+
safeTransformLimits: safeTransformLimits
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
module.exports = createTransformAPI
|