UNPKG

astl

Version:

AssemblyScript-STL (Standard Template Library, migrated from the C++)

619 lines (520 loc) 17.7 kB
import { Vector } from "./Vector"; import { ReverseIteratorBase } from "../internal/iterator/ReverseIteratorBase"; import { CMath } from "../internal/numeric/CMath"; import { ErrorGenerator } from "../internal/exception/ErrorGenerator"; import { Pair } from "../utility/Pair"; import { Repeater } from "../internal/iterator/disposable/Repeater"; import { distance } from "../iterator/global"; export class Deque<T> { private matrix_: Vector<Vector<T>>; private size_: usize; private capacity_: usize; /* --------------------------------------------------------- CONSTURCTORS --------------------------------------------------------- */ public constructor() { this.matrix_ = new Vector(); this.matrix_.push_back(new Vector()); this.matrix_.back().reserve(MIN_ROW_CAPACITY); this.size_ = 0; this.capacity_ = ROW_SIZE * MIN_ROW_CAPACITY; } @inline public assign<InputIterator> (first: InputIterator, last: InputIterator): void { if (this.empty() === false) this.clear(); this.insert_range<InputIterator>(this.end(), first, last); } @inline public assign_repeatedly(length: usize, value: T): void { if (this.empty() === false) this.clear(); this.insert_repeatedly(this.end(), length, value); } public clear(): void { this.matrix_ = new Vector(); this.matrix_.push_back(new Vector()); this.matrix_.back().reserve(MIN_ROW_CAPACITY); this.size_ = 0; this.capacity_ = 8; } @inline public resize(n: usize): void { this._Reserve(n, n); this.size_ = n; } @inline public reserve(capacity: usize): void { if (this.capacity_ < CMath.max(capacity, ROW_SIZE * MIN_ROW_CAPACITY)) this._Reserve(capacity, this.size()); } private _Reserve(capacity: usize, limit: usize): void { // FIX CAPACITY capacity = CMath.max(capacity, ROW_SIZE * MIN_ROW_CAPACITY); const length: usize = this._Compute_row_size(capacity); capacity = length * ROW_SIZE; // CREATE THE NEW MATRIX const matrix: Vector<Vector<T>> = new Vector(); matrix.reserve(ROW_SIZE); this._Insert_row(matrix.end(), length); // RE-FILL THE VALES if (limit !== 0) this._Fill_range(matrix, length, this.begin(), this.nth(limit)); // ASSIGN THE MEMBERS this.matrix_ = matrix; this.capacity_ = capacity; } private _Try_expand(plus: usize, limit: usize = this.size()): void { const required: usize = this.size() + plus; if (this.capacity()) return; const capacity: usize = CMath.max(required, this.capacity() * MAGNIFIER); this._Reserve(capacity, limit); } /* ========================================================= ACCESSORS - CAPACITIES - ELEMENTS - ITERATORS ============================================================ CAPACITIES --------------------------------------------------------- */ @inline public size(): usize { return this.size_; } @inline public empty(): boolean { return this.size() === 0; } @inline public capacity(): usize { return this.capacity_; } private _Compute_row_size(capacity: usize): usize { const value: f64 = capacity / <f64>ROW_SIZE; const ret: usize = <usize>Math.ceil(value); return ret; } /* --------------------------------------------------------- ELEMENTS --------------------------------------------------------- */ @inline @operator("[]") public at(index: usize): T { if (index >= this.size()) throw ErrorGenerator.excessive("Deque.at()", index, this.size()); const tuple: Pair<usize, usize> = this._Fetch_index(index); return this.matrix_.at(tuple.first).at(tuple.second); } @inline @operator("[]=") public set(index: usize, val: T): void { if (index >= this.size()) throw ErrorGenerator.excessive("Deque.set()", index, this.size()); const tuple: Pair<usize, usize> = this._Fetch_index(index); this.matrix_.at(tuple.first).set(tuple.second, val); } @inline public front(): T { return this.at(0); } @inline public back(): T { return this.at(this.size() - 1); } private _Fetch_index(index: usize): Pair<usize, usize> { // Fetch row and column's index. let row: usize; for (row = 0; row < this.matrix_.size(); row++) { const vector: Vector<T> = this.matrix_.at(row); if (index < vector.size()) break; index -= vector.size(); } if (row === this.matrix_.size()) row--; return new Pair(row, index); } /* --------------------------------------------------------- ITERATORS --------------------------------------------------------- */ @inline public nth(index: usize): Deque.Iterator<T> { return new Deque.Iterator(this, index); } @inline public begin(): Deque.Iterator<T> { return this.nth(0); } @inline public end(): Deque.Iterator<T> { return this.nth(this.size()); } @inline public rbegin(): Deque.ReverseIterator<T> { return this.end().reverse(); } @inline public rend(): Deque.ReverseIterator<T> { return this.begin().reverse(); } /* ========================================================= ELEMENTS I/O - INSERT - ERASE - SWAP ============================================================ INSERT --------------------------------------------------------- */ public push_front(val: T): void { // EXPAND CAPACITY this._Try_expand(1); const length: usize = this._Compute_row_size(this.capacity()); let top: Vector<T> = this.matrix_.front(); // ADD A NEW ROW IF REQUIRED if (top.size() >= length && this.matrix_.size() < ROW_SIZE) top = this._Insert_row(this.matrix_.begin(), length); // INSERT ITEM top.insert(top.begin(), val); ++this.size_; } public push_back(val: T): void { // EXPAND CAPACITY this._Try_expand(1); const length: usize = this._Compute_row_size(this.capacity()); let bottom: Vector<T> = this.matrix_.back(); // ADD A NEW ROW IF REQUIRED if (bottom.size() >= length && this.matrix_.size() < ROW_SIZE) bottom = this._Insert_row(this.matrix_.end(), length); // INSERT ITEM bottom.push_back(val); ++this.size_; } @inline public insert(pos: Deque.Iterator<T>, val: T): Deque.Iterator<T> { return this.insert_repeatedly(pos, 1, val); } public insert_repeatedly(pos: Deque.Iterator<T>, n: usize, val: T): Deque.Iterator<T> { const first: Repeater<T> = new Repeater(0, val); const last: Repeater<T> = new Repeater(n, val); return this.insert_range(pos, first, last); } public insert_range<InputIterator> (pos: Deque.Iterator<T>, first: InputIterator, last: InputIterator): Deque.Iterator<T> { const plus: usize = distance(first, last); if (plus === 0) return pos; if (pos == this.end()) { this._Try_expand(plus); this._Fill_range(this.matrix_, this._Compute_row_size(this.capacity()), first, last); this.size_ += plus; } else if (this.capacity() >= this.size() + plus) { const tuple: Pair<usize, usize> = this._Fetch_index(pos.index()); const row: Vector<T> = this.matrix_.at(tuple.first); row.insert_range(row.nth(tuple.second), first, last); this.size_ += plus; } else { const deque: Deque<T> = new Deque(); deque._Reserve(CMath.max(this.size() + plus, this.capacity() * MAGNIFIER), 0); deque.insert_range(deque.end(), this.begin(), pos); deque.insert_range(deque.end(), first, last); deque.insert_range(deque.end(), pos, this.end()); this.swap(deque); } return pos; } private _Insert_row(pos: Vector.Iterator<Vector<T>>, length: usize): Vector<T> { const row: Vector<T> = new Vector<T>(); row.reserve(length); pos.source().insert(pos, row); return row; } private _Fill_range<InputIterator> (matrix: Vector<Vector<T>>, length: usize, first: InputIterator, last: InputIterator): void { for (; first != last; first = first.next()) { let row: Vector<T> = matrix.back(); if (row.size() >= length) row = this._Insert_row(matrix.end(), length); row.push_back(first.value); } } /* --------------------------------------------------------- ERASE --------------------------------------------------------- */ public pop_front(): void { // VALIDATE if (this.empty() === true) throw ErrorGenerator.empty("Deque.pop_front()"); // ERASE THE FIRST ELEMENT const top: Vector<T> = this.matrix_.front(); top.erase(top.begin()); if (top.empty() === true && this.matrix_.size() > 1) this.matrix_.erase(this.matrix_.begin()); // SHRINK THE SIZE --this.size_; } public pop_back(): void { // VALIDATE if (this.empty() === true) throw ErrorGenerator.empty("Deque.pop_back()"); // ERASE THE LAST ELEMENT const bottom: Vector<T> = this.matrix_.back(); bottom.pop_back(); if (bottom.empty() === true && this.matrix_.size() > 1) this.matrix_.pop_back(); // SHRINK THE SIZE --this.size_; } public erase(first: Deque.Iterator<T>, last: Deque.Iterator<T> = first.next()): Deque.Iterator<T> { if (first.index() >= last.index()) return first; let remained: usize = CMath.min(this.size(), last.index()) - first.index(); this.size_ -= remained; let tuple: Pair<usize, usize> | null = null; let top: Vector<T> | null = null; let bottom: Vector<T> | null = null; while (remained !== 0) { // LIST UP THE TARGET ROW tuple = this._Fetch_index(first.index()); const row: Vector<T> = this.matrix_.at(tuple.first); const col: usize = tuple.second; // ERASE FROM THE ROW const length: usize = CMath.min(remained, row.size() - col); row.erase(row.nth(col), row.nth(col + length)); remained -= length; // TO MERGE if (row.size() !== 0) if (top !== null) top = row; else bottom = row; // ERASE THE ENTIRE ROW IF REQUIRED if (row.empty() === true && this.matrix_.size() > 1) this.matrix_.erase(this.matrix_.nth(tuple.first)); } // MERGE FIRST AND SECOND ROW IF POSSIBLE if (top !== null && bottom !== null && top.size() + bottom.size() <= this._Compute_row_size(this.capacity())) { top.insert_range(top.end(), bottom.begin(), bottom.end()); this.matrix_.erase(this.matrix_.nth(tuple!.first + 1)); } return first; } /* --------------------------------------------------------- SWAP --------------------------------------------------------- */ public swap(obj: Deque<T>): void { // MATRIX const matrix: Vector<Vector<T>> = this.matrix_; this.matrix_ = obj.matrix_; obj.matrix_ = matrix; // SIZE const size: usize = this.size_; this.size_ = obj.size_; obj.size_ = size; // CAPACITY const capacity: usize = this.capacity_; this.capacity_ = obj.capacity_; obj.capacity_= capacity; } } export namespace Deque { export class Iterator<T> { private readonly source_: Deque<T>; private readonly index_: usize; /* --------------------------------------------------------- CONSTRUCTORS --------------------------------------------------------- */ public constructor(source: Deque<T>, index: usize) { this.source_ = source; this.index_ = index; } @inline public reverse(): ReverseIterator<T> { return new ReverseIterator(this); } @inline public prev(): Iterator<T> { return this.advance(-1); } @inline public next(): Iterator<T> { return this.advance(1); } @inline public advance(n: isize): Iterator<T> { return this.source_.nth(this.index_ + n); } /* --------------------------------------------------------- ACCESSORS --------------------------------------------------------- */ @inline public source(): Deque<T> { return this.source_; } @inline public index(): usize { return this.index_; } @inline public get value(): T { return this.source_.at(this.index_); } @inline public set value(val: T) { this.source_.set(this.index_, val); } /* --------------------------------------------------------- OPERATORS --------------------------------------------------------- */ @inline @operator("==") public equals(obj: Iterator<T>): boolean { return this.source_ === obj.source_ && this.index_ === obj.index_; } @inline @operator("<") public less(obj: Iterator<T>): boolean { return this.index_ < obj.index_; } @inline @operator("!=") protected __not_equals(obj: Iterator<T>): boolean { return !this.equals(obj); } @inline @operator("<=") protected __less_equals(obj: Iterator<T>): boolean { return this.source_ === obj.source_ && this.index_ <= obj.index_; } @inline @operator(">") protected __greater(obj: Iterator<T>): boolean { return this.index_ > obj.index_; } @inline @operator(">=") protected __greater_equals(obj: Iterator<T>): boolean { return this.source_ === obj.source_ && this.index_ >= obj.index_; } } export class ReverseIterator<T> extends ReverseIteratorBase<T, Deque<T>, Iterator<T>, ReverseIterator<T>, T> { /* --------------------------------------------------------- ACCESSORS --------------------------------------------------------- */ @inline public advance(n: isize): ReverseIterator<T> { return this.base().advance(-n).reverse(); } @inline public index(): usize { return this.base().index(); } @inline public get value(): T { return this.base_.value; } @inline public set value(val: T) { this.base_.value = val; } /* --------------------------------------------------------- OPERATORS --------------------------------------------------------- */ @inline @operator("<") public less(obj: ReverseIterator<T>): boolean { return this.index() > obj.index(); } @inline @operator("<=") protected __less_equals(obj: ReverseIterator<T>): boolean { return this.source() === obj.source() && this.index() >= obj.index(); } @inline @operator(">") protected __greater(obj: ReverseIterator<T>): boolean { return this.index() < obj.index(); } @inline @operator(">=") protected __greater_equals(obj: ReverseIterator<T>): boolean { return this.source() === obj.source() && this.index() <= obj.index(); } } } @inline const ROW_SIZE: usize = 8; @inline const MIN_ROW_CAPACITY: usize = 4; @inline const MAGNIFIER: usize = 2;