feat(Vector)

This commit is contained in:
2025-07-23 10:36:50 +03:00
parent 83c491ff6f
commit aca4539ce4
21 changed files with 1103 additions and 1533 deletions

View File

@ -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
View 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)

View File

@ -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() {

View File

@ -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"

View File

@ -8,4 +8,4 @@ mixinClasses(BidirectionalIterator, ForwardIterator)
BidirectionalIterator.is = function (obj, ...args) {
return ForwardIterator.is(obj, ...args) && satisfiesConcept(obj, ['dec'], [], ...args)
}
}

View File

@ -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)

View 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)
}

View File

@ -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;
}