feat(Vector)
This commit is contained in:
@ -121,6 +121,14 @@ export class ListIterator {
|
||||
this._item = rhs._item
|
||||
return this
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.deref().value
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
return this.deref().value = value
|
||||
}
|
||||
|
||||
deref() {
|
||||
return this._item
|
||||
|
||||
158
src/Vector.js
Normal file
158
src/Vector.js
Normal file
@ -0,0 +1,158 @@
|
||||
import { SequenceContainer } from "./containers/Sequence"
|
||||
import { RandomAccessIterator } from "./iterators/RandomAccess"
|
||||
import { mixinClasses } from "./utils/mixin"
|
||||
|
||||
export class Vector {
|
||||
|
||||
constructor(...args) {
|
||||
this._array = []
|
||||
if (args.length >= 1) {
|
||||
this.assign(...args)
|
||||
}
|
||||
}
|
||||
|
||||
move(rhs) {
|
||||
this._array = rhs._array
|
||||
rhs._array = undefined
|
||||
}
|
||||
|
||||
size() {
|
||||
return this._array.length
|
||||
}
|
||||
|
||||
begin() {
|
||||
return new VectorIterator(this._array, 0)
|
||||
}
|
||||
|
||||
end() {
|
||||
return new VectorIterator(this._array, this._array.length)
|
||||
}
|
||||
|
||||
get(idx) {
|
||||
if (idx < 0 || idx >= this._array.length)
|
||||
throw new Error('out of order')
|
||||
|
||||
return this.begin().add(idx).value
|
||||
}
|
||||
|
||||
set(idx, value) {
|
||||
if (idx < 0 || idx >= this._array.length)
|
||||
throw new Error('out of order')
|
||||
|
||||
return this.begin().add(idx).value = value
|
||||
}
|
||||
|
||||
resize(size, value) {
|
||||
let prev_size = this._array.length
|
||||
this._array.length = size
|
||||
|
||||
if (value === undefined)
|
||||
return
|
||||
|
||||
while (prev_size < size) {
|
||||
this._array[prev_size] = value
|
||||
prev_size++
|
||||
}
|
||||
}
|
||||
|
||||
_shiftRight(dest, generator, offset) {
|
||||
const prev_size = this._array.length
|
||||
this._array.length += offset
|
||||
let idx = dest._idx
|
||||
|
||||
for (let i = idx; i < prev_size; i++) {
|
||||
this._array[i + offset] = this._array[i]
|
||||
}
|
||||
|
||||
for (const value of generator) {
|
||||
this._array[idx] = value
|
||||
idx++
|
||||
}
|
||||
|
||||
return new VectorIterator(this._array, dest._idx)
|
||||
}
|
||||
|
||||
_shiftLeft(dest, _, offset) {
|
||||
let idx = dest._idx - offset
|
||||
|
||||
for (let i = 0; i < offset; i++) {
|
||||
this._array[idx + i] = this._array[dest._idx + i]
|
||||
}
|
||||
|
||||
this._array.length -= offset
|
||||
|
||||
return new VectorIterator(this._array, idx)
|
||||
}
|
||||
}
|
||||
|
||||
Vector.from = function(obj) {
|
||||
const vector = new Vector()
|
||||
|
||||
if (typeof obj.length == 'number') {
|
||||
vector.resize(obj.length)
|
||||
} else if (typeof obj.size == 'function') {
|
||||
vector.resize(obj.size())
|
||||
} else {
|
||||
for (const value of obj) {
|
||||
vector.pushBack(value)
|
||||
}
|
||||
return vector
|
||||
}
|
||||
|
||||
let idx = 0
|
||||
|
||||
for (const value of obj) {
|
||||
vector.set(idx, value)
|
||||
idx++
|
||||
}
|
||||
|
||||
return vector
|
||||
}
|
||||
|
||||
mixinClasses(Vector, SequenceContainer)
|
||||
|
||||
export class VectorIterator {
|
||||
|
||||
constructor(array, idx) {
|
||||
this._array = array
|
||||
this._idx = idx
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new VectorIterator(this._array, this._idx)
|
||||
}
|
||||
|
||||
copy(rhs) {
|
||||
this._array = rhs._array
|
||||
this._idx = rhs._idx
|
||||
}
|
||||
|
||||
sub(arg) {
|
||||
if (arg instanceof VectorIterator) {
|
||||
return this._idx - arg._idx
|
||||
} else if (typeof arg == 'number') {
|
||||
this._idx -= arg
|
||||
return this
|
||||
} else {
|
||||
throw new Error('incorrect args')
|
||||
}
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.deref()
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
return this._array[this._idx] = value
|
||||
}
|
||||
|
||||
deref() {
|
||||
return this._array[this._idx]
|
||||
}
|
||||
|
||||
eq(rhs) {
|
||||
return this._array == rhs._array && this._idx == rhs._idx
|
||||
}
|
||||
}
|
||||
|
||||
mixinClasses(VectorIterator, RandomAccessIterator)
|
||||
@ -1,5 +1,6 @@
|
||||
import { BidirectionalIterator } from "../iterators/Bidirectional"
|
||||
import { getCloneFunc, satisfiesConcept } from "../utils/concept"
|
||||
import { ForwardIterator } from "../iterators/Forward"
|
||||
import { RandomAccessIterator } from "../iterators/RandomAccess"
|
||||
import { satisfiesConcept } from "../utils/concept"
|
||||
|
||||
export class SequenceContainer {
|
||||
clone() {
|
||||
@ -39,40 +40,45 @@ export class SequenceContainer {
|
||||
|
||||
insert(dest, arg2, arg3) {
|
||||
if (
|
||||
BidirectionalIterator.is(arg2) &&
|
||||
BidirectionalIterator.is(arg3)
|
||||
ForwardIterator.is(arg2) &&
|
||||
ForwardIterator.is(arg3)
|
||||
) {
|
||||
return this._shiftRight(dest,
|
||||
{
|
||||
[Symbol.iterator]: () => {
|
||||
const local_begin = arg2.clone()
|
||||
return {
|
||||
next() {
|
||||
const res = {
|
||||
done: local_begin.eq(arg3),
|
||||
value: local_begin.value,
|
||||
}
|
||||
local_begin.inc()
|
||||
return res
|
||||
const generator = {
|
||||
[Symbol.iterator]: () => {
|
||||
const local_begin = arg2.clone()
|
||||
return {
|
||||
next() {
|
||||
const res = {
|
||||
done: local_begin.eq(arg3),
|
||||
value: local_begin.value,
|
||||
}
|
||||
local_begin.inc()
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if (
|
||||
RandomAccessIterator.is(arg2) &&
|
||||
RandomAccessIterator.is(arg3)
|
||||
) {
|
||||
return this._shiftRight(dest, generator, arg3.sub(arg2))
|
||||
} else {
|
||||
return this._shiftRight(dest, generator)
|
||||
}
|
||||
} else if (
|
||||
typeof arg3 == 'number' && arg3 >= 0 ||
|
||||
arg3 === undefined
|
||||
arg2 !== undefined && arg3 === undefined
|
||||
) {
|
||||
return this._shiftRight(dest,
|
||||
{
|
||||
[Symbol.iterator]: () => {
|
||||
let local_n = arg3 ?? 1
|
||||
return {
|
||||
next: () => ({ done: local_n-- <= 0, value: arg2 })
|
||||
}
|
||||
const generator = {
|
||||
[Symbol.iterator]: () => {
|
||||
let local_n = arg3 ?? 1
|
||||
return {
|
||||
next: () => ({ done: local_n-- <= 0, value: arg2 })
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
return this._shiftRight(dest, generator, arg3 ?? 1)
|
||||
} else {
|
||||
throw new Error('incorrect args')
|
||||
}
|
||||
@ -87,8 +93,13 @@ export class SequenceContainer {
|
||||
}
|
||||
|
||||
erase(begin, end = begin.clone().inc()) {
|
||||
return this._shiftLeft(end,
|
||||
{
|
||||
if (
|
||||
RandomAccessIterator.is(begin) &&
|
||||
RandomAccessIterator.is(end)
|
||||
) {
|
||||
return this._shiftLeft(end, undefined, end.sub(begin))
|
||||
} else {
|
||||
return this._shiftLeft(end, {
|
||||
[Symbol.iterator]: () => {
|
||||
let local_begin = begin.clone()
|
||||
return {
|
||||
@ -101,8 +112,8 @@ export class SequenceContainer {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
export { ForwardIterator } from "./iterators/Forward"
|
||||
export { BidirectionalIterator } from "./iterators/Bidirectional"
|
||||
export { RandomAccessIterator } from "./iterators/RandomAccess"
|
||||
export { SequenceContainer } from "./containers/Sequence"
|
||||
export { List, ListIterator, ListItem } from "./List"
|
||||
export { List, ListIterator, ListItem } from "./List"
|
||||
export { Vector, VectorIterator } from "./Vector"
|
||||
|
||||
@ -8,4 +8,4 @@ mixinClasses(BidirectionalIterator, ForwardIterator)
|
||||
|
||||
BidirectionalIterator.is = function (obj, ...args) {
|
||||
return ForwardIterator.is(obj, ...args) && satisfiesConcept(obj, ['dec'], [], ...args)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,14 +5,6 @@ export class ForwardIterator {
|
||||
return this.copy(rhs)
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.deref().value
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
return this.deref().value = value
|
||||
}
|
||||
|
||||
neq(rhs) {
|
||||
return !this.eq(rhs)
|
||||
}
|
||||
@ -22,13 +14,13 @@ ForwardIterator.is = function (obj, ...args) {
|
||||
const pure_virtual = [
|
||||
'clone',
|
||||
'copy',
|
||||
'value',
|
||||
'deref',
|
||||
'inc',
|
||||
'eq'
|
||||
'eq',
|
||||
]
|
||||
const virtual = [
|
||||
'move',
|
||||
'value',
|
||||
'neq',
|
||||
]
|
||||
return satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
||||
|
||||
44
src/iterators/RandomAccess.js
Normal file
44
src/iterators/RandomAccess.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { satisfiesConcept } from "../utils/concept";
|
||||
import { mixinClasses } from "../utils/mixin";
|
||||
import { BidirectionalIterator } from "./Bidirectional";
|
||||
|
||||
export class RandomAccessIterator {
|
||||
add(offset) {
|
||||
return this.sub( - offset)
|
||||
}
|
||||
|
||||
cmp(rhs) {
|
||||
return this.sub(rhs)
|
||||
}
|
||||
|
||||
get(idx) {
|
||||
return this.clone().add(idx).value
|
||||
}
|
||||
|
||||
set(idx, value) {
|
||||
return this.clone().add(idx).value = value
|
||||
}
|
||||
|
||||
inc() {
|
||||
return this.add(1)
|
||||
}
|
||||
|
||||
dec() {
|
||||
return this.sub(1)
|
||||
}
|
||||
}
|
||||
|
||||
mixinClasses(RandomAccessIterator, BidirectionalIterator)
|
||||
|
||||
RandomAccessIterator.is = function(obj, ...args) {
|
||||
const pure_virtual = [
|
||||
'sub',
|
||||
]
|
||||
const virtual = [
|
||||
'add',
|
||||
'cmp',
|
||||
'get',
|
||||
'set',
|
||||
]
|
||||
return BidirectionalIterator.is(obj, ...args) && satisfiesConcept(obj, pure_virtual, virtual, ...args)
|
||||
}
|
||||
@ -1,28 +1,31 @@
|
||||
export function satisfiesConcept(obj, pure_virtual, virtual, debug) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const desc = Object.getOwnPropertyDescriptors(obj.constructor.prototype)
|
||||
|
||||
if (debug) {
|
||||
const missingMethods = []
|
||||
|
||||
pure_virtual.forEach((method) => {
|
||||
if (typeof obj[method] !== 'function') {
|
||||
if (method in desc == false) {
|
||||
missingMethods.push(method)
|
||||
}
|
||||
})
|
||||
|
||||
virtual.forEach((method) => {
|
||||
if (!(method in obj)) {
|
||||
if (method in obj == false) {
|
||||
missingMethods.push(method)
|
||||
}
|
||||
})
|
||||
|
||||
if (missingMethods.length !== 0) {
|
||||
console.debug(obj.constructor.name, missingMethods)
|
||||
console.debug('this class doesn\'t have methods', obj.constructor.name, missingMethods)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if (!pure_virtual.every((method) => typeof obj[method] === 'function')) {
|
||||
if (!pure_virtual.every((method) => method in desc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user