astl
Version:
AssemblyScript-STL (Standard Template Library, migrated from the C++)
218 lines (179 loc) • 5.81 kB
text/typescript
import { Vector } from "../../container/Vector";
import { CMath } from "../numeric/CMath";
import { Hasher } from "../functional/Hasher";
import { BinaryPredicator } from "../functional/BinaryPredicator";
export class HashBuckets<Key, Elem>
{
private readonly hasher_: Hasher<Key>;
private readonly predicator_: BinaryPredicator<Key>;
private readonly fetcher_: (elem: Elem) => Key;
private max_load_factor_: f64;
private data_: Vector<Vector<Elem>>;
private size_: usize;
/* ---------------------------------------------------------
CONSTRUCTORS
--------------------------------------------------------- */
public constructor(hasher: Hasher<Key>, pred: BinaryPredicator<Key>, fetcher: (elem: Elem) => Key)
{
this.hasher_ = hasher;
this.predicator_ = pred;
this.fetcher_ = fetcher;
this.max_load_factor_ = DEFAULT_MAX_FACTOR;
this.data_ = new Vector();
this.initialize();
}
public clear(): void
{
this.data_.clear();
this.initialize();
}
public rehash(length: usize): void
{
length = CMath.max(length, MIN_BUCKET_COUNT);
const log: f64 = Math.log2(<f64>length);
if (log !== Math.floor(log))
length = <usize>(Math.pow(2, Math.ceil(log)));
// CREATE NEW BUCKET
const data: Vector<Vector<Elem>> = new Vector();
data.reserve(length);
for (let i: usize = 0; i < length; ++i)
data.push_back(new Vector());
// MIGRATE ELEMENTS TO THE NEW BUCKET
for (let i: usize = 0; i < this.data_.size(); ++i)
{
const row: Vector<Elem> = this.data_.at(i);
for (let j: usize = 0; j < row.size(); ++j)
{
const element: Elem = row.at(j);
const index: usize = this.hasher_(this.fetcher_(element)) % length;
data.at(index).push_back(element);
}
}
// DO CHANGE THE BUCKET
this.data_ = data;
}
public reserve(length: usize): void
{
if (length > this.capacity())
{
length = <usize>(length / this.max_load_factor_);
this.rehash(length);
}
}
private initialize(): void
{
this.size_ = 0;
for (let i: usize = 0; i < MIN_BUCKET_COUNT; ++i)
this.data_.push_back(new Vector());
}
/* ---------------------------------------------------------
ACCESSORS
--------------------------------------------------------- */
public size(): usize
{
return this.size_;
}
public row_size(): usize
{
return this.data_.size();
}
public capacity(): usize
{
return <usize>(this.row_size() * this.max_load_factor_);
}
public at(index: usize): Vector<Elem>
{
return this.data_.at(index);
}
public load_factor(): f64
{
return this.size_ / this.row_size();
}
public max_load_factor(): f64
{
return this.max_load_factor_;
}
public set_max_load_factor(z: f64): void
{
this.max_load_factor_ = z;
}
public hash_function(): Hasher<Key>
{
return this.hasher_;
}
public key_eq(): BinaryPredicator<Key>
{
return this.predicator_;
}
/* ---------------------------------------------------------
FINDERS
--------------------------------------------------------- */
private index_by_key(key: Key): usize
{
return this.hash_function()(key) & (this.row_size() - 1);
}
private index_by_value(elem: Elem): usize
{
return this.index_by_key(this.fetcher_(elem));
}
public find(key: Key): Elem | null
{
const index: usize = this.index_by_key(key);
const bucket: Vector<Elem> = this.at(index);
for (let i: usize = 0; i < bucket.size(); ++i)
{
const it: Elem = bucket.at(i);
if (this.predicator_(key, this.fetcher_(it)) === true)
return it;
}
return null;
}
public count(key: Key): usize
{
const index: usize = this.index_by_key(key);
const bucket: Vector<Elem> = this.at(index);
let ret: usize = 0;
for (let i: usize = 0; i < bucket.size(); ++i)
if (this.key_eq()(key, this.fetcher_(bucket.at(i))) === true)
++ret;
return ret;
}
/* ---------------------------------------------------------
ELEMENTS I/O
--------------------------------------------------------- */
public insert(val: Elem): void
{
const capacity: usize = this.capacity();
if (++this.size_ > capacity)
this.rehash(capacity * 2);
const index: usize = this.index_by_value(val);
const bucket: Vector<Elem> = this.data_.at(index);
bucket.push_back(val);
}
public erase(val: Elem): boolean
{
const index: usize = this.index_by_value(val);
const bucket: Vector<Elem> = this.data_.at(index);
for (let i: usize = 0; i < bucket.size(); ++i)
if (bucket.at(i) === val)
{
bucket.erase(bucket.nth(i));
--this.size_;
return true;
}
return false;
}
}
const MIN_BUCKET_COUNT: usize = 8;
const DEFAULT_MAX_FACTOR: f64 = 1.0;