//================================================================ /** * @packageDocumentation * @module std */ //================================================================ import { UniqueSet } from "../base/container/UniqueSet"; import { IHashSet } from "../base/container/IHashSet"; import { IHashContainer } from "../internal/container/associative/IHashContainer"; import { SetElementList } from "../internal/container/associative/SetElementList"; import { SetHashBuckets } from "../internal/hash/SetHashBuckets"; import { IForwardIterator } from "../iterator/IForwardIterator"; import { Pair } from "../utility/Pair"; import { BinaryPredicator } from "../internal/functional/BinaryPredicator"; import { Hasher } from "../internal/functional/Hasher"; import { Temporary } from "../internal/functional/Temporary"; /** * Unique-key Set based on Hash buckets. * * @author Jeongho Nam - https://github.com/samchon */ export class HashSet extends UniqueSet< Key, HashSet, HashSet.Iterator, HashSet.ReverseIterator > implements IHashSet> { private buckets_!: SetHashBuckets>; /* ========================================================= CONSTRUCTORS & SEMI-CONSTRUCTORS - CONSTRUCTORS - ASSIGN & CLEAR ============================================================ CONSTURCTORS --------------------------------------------------------- */ /** * Default Constructor. * * @param hash An unary function returns hash code. Default is {hash}. * @param equal A binary function predicates two arguments are equal. Default is {@link equal_to}. */ public constructor(hash?: Hasher, equal?: BinaryPredicator); /** * Initializer Constructor. * * @param items Items to assign. * @param hash An unary function returns hash code. Default is {hash}. * @param equal A binary function predicates two arguments are equal. Default is {@link equal_to}. */ public constructor( items: Key[], hash?: Hasher, equal?: BinaryPredicator, ); /** * Copy Constructor. * * @param obj Object to copy. */ public constructor(obj: HashSet); /** * Range Constructor. * * @param first Input iterator of the first position. * @param last Input iterator of the last position. * @param hash An unary function returns hash code. Default is {hash}. * @param equal A binary function predicates two arguments are equal. Default is {@link equal_to}. */ public constructor( first: Readonly>, last: Readonly>, hash?: Hasher, equal?: BinaryPredicator, ); public constructor(...args: any[]) { super((thisArg) => new SetElementList(thisArg)); IHashContainer.construct< Key, Key, HashSet, HashSet.Iterator, HashSet.ReverseIterator, Key >( this, HashSet, (hash, pred) => { this.buckets_ = new SetHashBuckets(this, hash, pred); }, ...args, ); } /* --------------------------------------------------------- ASSIGN & CLEAR --------------------------------------------------------- */ /** * @inheritDoc */ public clear(): void { this.buckets_.clear(); super.clear(); } /** * @inheritDoc */ public swap(obj: HashSet): void { // SWAP CONTENTS [this.data_, obj.data_] = [obj.data_, this.data_]; SetElementList._Swap_associative( this.data_ as Temporary, obj.data_ as Temporary, ); // SWAP BUCKETS SetHashBuckets._Swap_source(this.buckets_, obj.buckets_); [this.buckets_, obj.buckets_] = [obj.buckets_, this.buckets_]; } /* ========================================================= ACCESSORS - MEMBER - HASH ============================================================ MEMBER --------------------------------------------------------- */ /** * @inheritDoc */ public find(key: Key): HashSet.Iterator { return this.buckets_.find(key); } /** * @inheritDoc */ public begin(): HashSet.Iterator; /** * @inheritDoc */ public begin(index: number): HashSet.Iterator; public begin(index: number | null = null): HashSet.Iterator { if (index === null) return super.begin(); else return this.buckets_.at(index)[0]; } /** * @inheritDoc */ public end(): HashSet.Iterator; /** * @inheritDoc */ public end(index: number): HashSet.Iterator; public end(index: number | null = null): HashSet.Iterator { if (index === null) return super.end(); else { const bucket = this.buckets_.at(index); return bucket[bucket.length - 1].next(); } } /** * @inheritDoc */ public rbegin(): HashSet.ReverseIterator; /** * @inheritDoc */ public rbegin(index: number): HashSet.ReverseIterator; public rbegin(index: number | null = null): HashSet.ReverseIterator { return this.end(index!).reverse(); } /** * @inheritDoc */ public rend(): HashSet.ReverseIterator; /** * @inheritDoc */ public rend(index: number): HashSet.ReverseIterator; public rend(index: number | null = null): HashSet.ReverseIterator { return this.begin(index!).reverse(); } /* --------------------------------------------------------- HASH --------------------------------------------------------- */ /** * @inheritDoc */ public bucket_count(): number { return this.buckets_.length(); } /** * @inheritDoc */ public bucket_size(n: number): number { return this.buckets_.at(n).length; } /** * @inheritDoc */ public load_factor(): number { return this.buckets_.load_factor(); } /** * @inheritDoc */ public hash_function(): Hasher { return this.buckets_.hash_function(); } /** * @inheritDoc */ public key_eq(): BinaryPredicator { return this.buckets_.key_eq(); } /** * @inheritDoc */ public bucket(key: Key): number { return this.hash_function()(key) % this.buckets_.length(); } /** * @inheritDoc */ public max_load_factor(): number; /** * @inheritDoc */ public max_load_factor(z: number): void; public max_load_factor(z: number | null = null): any { return this.buckets_.max_load_factor(z!); } /** * @inheritDoc */ public reserve(n: number): void { this.buckets_.reserve(n); } /** * @inheritDoc */ public rehash(n: number): void { this.buckets_.rehash(n); } /* ========================================================= ELEMENTS I/O - INSERT - POST-PROCESS - SWAP ============================================================ INSERT --------------------------------------------------------- */ protected _Insert_by_key(key: Key): Pair, boolean> { // TEST WHETHER EXIST let it: HashSet.Iterator = this.find(key); if (it.equals(this.end()) === false) return new Pair(it, false); // INSERT this.data_.push(key); it = it.prev(); // POST-PROCESS this._Handle_insert(it, it.next()); return new Pair(it, true); } protected _Insert_by_hint( hint: HashSet.Iterator, key: Key, ): HashSet.Iterator { // FIND DUPLICATED KEY let it: HashSet.Iterator = this.find(key); if (it.equals(this.end()) === true) { // INSERT it = this.data_.insert(hint, key); // POST-PROCESS this._Handle_insert(it, it.next()); } return it; } /* --------------------------------------------------------- POST-PROCESS --------------------------------------------------------- */ protected _Handle_insert( first: HashSet.Iterator, last: HashSet.Iterator, ): void { for (; !first.equals(last); first = first.next()) this.buckets_.insert(first); } protected _Handle_erase( first: HashSet.Iterator, last: HashSet.Iterator, ): void { for (; !first.equals(last); first = first.next()) this.buckets_.erase(first); } } /** * */ export namespace HashSet { // HEAD /** * Iterator of {@link HashSet} */ export type Iterator = SetElementList.Iterator< Key, true, HashSet >; /** * Reverse iterator of {@link HashSet} */ export type ReverseIterator = SetElementList.ReverseIterator< Key, true, HashSet >; // BODY export const Iterator = SetElementList.Iterator; export const ReverseIterator = SetElementList.ReverseIterator; }