Skip to content

Instantly share code, notes, and snippets.

@tosuke
Last active September 10, 2019 16:33
Show Gist options
  • Save tosuke/d959dd8b961c0d1ad533381e7d868439 to your computer and use it in GitHub Desktop.
Save tosuke/d959dd8b961c0d1ad533381e7d868439 to your computer and use it in GitHub Desktop.
インクリメンタルなデシリアライザ
class Stack<T> {
private _intenal: T[]
private _pointer: number = -1
constructor(size: number = 0) {
this._intenal = new Array(size)
}
get top(): T | undefined {
return this._intenal[this._pointer]
}
get empty(): boolean {
return this._pointer === -1
}
push(value: T): void {
this._pointer++
if (this._intenal.length > this._pointer) {
this._intenal[this._pointer] = value
} else {
this._intenal.push(value)
}
}
pop(): T | undefined {
return this._intenal[this._pointer--]
}
clear(): void {
this._pointer = -1
}
}
type StackItem =
| {
type: 'ARRAY'
position: number
size: number
array: Array<unknown>
}
| {
type: 'MAP_KEY' | 'MAP_VALUE'
remains: number
key: string | null
map: Record<string, unknown>
}
class Deserializer {
private stack: Stack<StackItem>
private value: unknown
constructor(depth: number = 8) {
this.stack = new Stack(depth)
}
getResult(): unknown {
if (!this.stack.empty) throw new Error('Cannot get result when processing')
return this.value
}
setValue(value: unknown) {
this.value = value
let item: StackItem | undefined
while ((item = this.stack.top)) {
switch (item.type) {
case 'ARRAY':
item.array[item.position++] = this.value
if (item.position !== item.array.length) return
this.value = item.array
this.stack.pop()
continue
case 'MAP_KEY':
if (typeof this.value !== 'string') throw new Error('The type of key must be string')
item.key = this.value
item.type = 'MAP_VALUE'
return
case 'MAP_VALUE':
item.map[item.key!] = this.value
if (--item.remains !== 0) {
item.type = 'MAP_KEY'
return
} else {
this.value = item.map
this.stack.pop()
continue
}
default:
return
}
}
}
enterArray(size: number) {
this.stack.push({ type: 'ARRAY', position: 0, size: size | 0, array: new Array(size) })
}
enterMap(size: number) {
if (size === 0) {
this.value = {}
return
}
this.stack.push({ type: 'MAP_KEY', remains: size | 0, key: null, map: {} })
}
}
const d = new Deserializer()
d.enterMap(4)
d.setValue('id')
d.setValue(1)
d.setValue('text')
d.setValue('hogehoge')
d.setValue('user')
d.enterMap(2)
d.setValue('id')
d.setValue(1)
d.setValue('name')
d.setValue('admin')
d.setValue('array')
d.enterArray(3)
d.setValue(1)
d.setValue(2)
d.setValue(3)
console.log(d.getResult())
@phungkhanh90
Copy link

yea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment