| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| import { Vector } from '../vector'; |
| import { IntBuilder } from './int'; |
| import { Dictionary, DataType } from '../type'; |
| import { Builder, BuilderOptions } from '../builder'; |
| |
| type DictionaryHashFunction = (x: any) => string | number; |
| |
| export interface DictionaryBuilderOptions<T extends DataType = any, TNull = any> extends BuilderOptions<T, TNull> { |
| dictionaryHashFunction?: DictionaryHashFunction; |
| } |
| |
| /** @ignore */ |
| export class DictionaryBuilder<T extends Dictionary, TNull = any> extends Builder<T, TNull> { |
| |
| protected _dictionaryOffset: number; |
| protected _dictionary?: Vector<T['dictionary']>; |
| protected _keysToIndices: { [key: string]: number }; |
| public readonly indices: IntBuilder<T['indices']>; |
| public readonly dictionary: Builder<T['dictionary']>; |
| |
| constructor({ 'type': type, 'nullValues': nulls, 'dictionaryHashFunction': hashFn }: DictionaryBuilderOptions<T, TNull>) { |
| super({ type: new Dictionary(type.dictionary, type.indices, type.id, type.isOrdered) as T }); |
| this._nulls = <any> null; |
| this._dictionaryOffset = 0; |
| this._keysToIndices = Object.create(null); |
| this.indices = Builder.new({ 'type': this.type.indices, 'nullValues': nulls }) as IntBuilder<T['indices']>; |
| this.dictionary = Builder.new({ 'type': this.type.dictionary, 'nullValues': null }) as Builder<T['dictionary']>; |
| if (typeof hashFn === 'function') { |
| this.valueToKey = hashFn; |
| } |
| } |
| |
| public get values() { return this.indices.values; } |
| public get nullCount() { return this.indices.nullCount; } |
| public get nullBitmap() { return this.indices.nullBitmap; } |
| public get byteLength() { return this.indices.byteLength + this.dictionary.byteLength; } |
| public get reservedLength() { return this.indices.reservedLength + this.dictionary.reservedLength; } |
| public get reservedByteLength() { return this.indices.reservedByteLength + this.dictionary.reservedByteLength; } |
| public isValid(value: T['TValue'] | TNull) { return this.indices.isValid(value); } |
| public setValid(index: number, valid: boolean) { |
| const indices = this.indices; |
| valid = indices.setValid(index, valid); |
| this.length = indices.length; |
| return valid; |
| } |
| public setValue(index: number, value: T['TValue']) { |
| const keysToIndices = this._keysToIndices; |
| const key = this.valueToKey(value); |
| let idx = keysToIndices[key]; |
| if (idx === undefined) { |
| keysToIndices[key] = idx = this._dictionaryOffset + this.dictionary.append(value).length - 1; |
| } |
| return this.indices.setValue(index, idx); |
| } |
| public flush() { |
| const type = this.type; |
| const prev = this._dictionary; |
| const curr = this.dictionary.toVector(); |
| const data = this.indices.flush().clone(type); |
| data.dictionary = prev ? prev.concat(curr) : curr; |
| this.finished || (this._dictionaryOffset += curr.length); |
| this._dictionary = data.dictionary as Vector<T['dictionary']>; |
| this.clear(); |
| return data; |
| } |
| public finish() { |
| this.indices.finish(); |
| this.dictionary.finish(); |
| this._dictionaryOffset = 0; |
| this._keysToIndices = Object.create(null); |
| return super.finish(); |
| } |
| public clear() { |
| this.indices.clear(); |
| this.dictionary.clear(); |
| return super.clear(); |
| } |
| public valueToKey(val: any): string | number { |
| return typeof val === 'string' ? val : `${val}`; |
| } |
| } |