restructer and move to esdoc

This commit is contained in:
Kevin Jahns
2018-03-06 03:17:36 +01:00
parent a9b610479d
commit bbc207aaa6
48 changed files with 223 additions and 227 deletions

151
src/Util/Binary/Decoder.js Normal file
View File

@@ -0,0 +1,151 @@
import ID from '../Util/ID/ID.js.js'
import { default as RootID, RootFakeUserID } from '../Util/ID/RootID.js.js'
/**
* A BinaryDecoder handles the decoding of an ArrayBuffer.
*/
export default class BinaryDecoder {
/**
* @param {Uint8Array|Buffer} buffer The binary data that this instance
* decodes.
*/
constructor (buffer) {
if (buffer instanceof ArrayBuffer) {
this.uint8arr = new Uint8Array(buffer)
} else if (
buffer instanceof Uint8Array ||
(
typeof Buffer !== 'undefined' && buffer instanceof Buffer
)
) {
this.uint8arr = buffer
} else {
throw new Error('Expected an ArrayBuffer or Uint8Array!')
}
this.pos = 0
}
/**
* Clone this decoder instance.
* Optionally set a new position parameter.
*/
clone (newPos = this.pos) {
let decoder = new BinaryDecoder(this.uint8arr)
decoder.pos = newPos
return decoder
}
/**
* Number of bytes.
*/
get length () {
return this.uint8arr.length
}
/**
* Skip one byte, jump to the next position.
*/
skip8 () {
this.pos++
}
/**
* Read one byte as unsigned integer.
*/
readUint8 () {
return this.uint8arr[this.pos++]
}
/**
* Read 4 bytes as unsigned integer.
*
* @return {number} An unsigned integer.
*/
readUint32 () {
let uint =
this.uint8arr[this.pos] +
(this.uint8arr[this.pos + 1] << 8) +
(this.uint8arr[this.pos + 2] << 16) +
(this.uint8arr[this.pos + 3] << 24)
this.pos += 4
return uint
}
/**
* Look ahead without incrementing position.
* to the next byte and read it as unsigned integer.
*
* @return {number} An unsigned integer.
*/
peekUint8 () {
return this.uint8arr[this.pos]
}
/**
* Read unsigned integer (32bit) with variable length.
* 1/8th of the storage is used as encoding overhead.
* * numbers < 2^7 is stored in one byte.
* * numbers < 2^14 is stored in two bytes.
*
* @return {number} An unsigned integer.
*/
readVarUint () {
let num = 0
let len = 0
while (true) {
let r = this.uint8arr[this.pos++]
num = num | ((r & 0b1111111) << len)
len += 7
if (r < 1 << 7) {
return num >>> 0 // return unsigned number!
}
if (len > 35) {
throw new Error('Integer out of range!')
}
}
}
/**
* Read string of variable length
* * varUint is used to store the length of the string
*
* @return {String} The read String.
*/
readVarString () {
let len = this.readVarUint()
let bytes = new Array(len)
for (let i = 0; i < len; i++) {
bytes[i] = this.uint8arr[this.pos++]
}
let encodedString = bytes.map(b => String.fromCodePoint(b)).join('')
return decodeURIComponent(escape(encodedString))
}
/**
* Look ahead and read varString without incrementing position
*/
peekVarString () {
let pos = this.pos
let s = this.readVarString()
this.pos = pos
return s
}
/**
* Read ID.
* * If first varUint read is 0xFFFFFF a RootID is returned.
* * Otherwise an ID is returned.
*
* @return ID
*/
readID () {
let user = this.readVarUint()
if (user === RootFakeUserID) {
// read property name and type id
const rid = new RootID(this.readVarString(), null)
rid.type = this.readVarUint()
return rid
}
return new ID(user, this.readVarUint())
}
}

144
src/Util/Binary/Encoder.js Normal file
View File

@@ -0,0 +1,144 @@
import { RootFakeUserID } from '../Util/ID/RootID.js.js'
const bits7 = 0b1111111
const bits8 = 0b11111111
/**
* A BinaryEncoder handles the encoding to an ArrayBuffer.
*/
export default class BinaryEncoder {
constructor () {
// TODO: implement chained Uint8Array buffers instead of Array buffer
this.data = []
}
/**
* The current length of the encoded data.
*/
get length () {
return this.data.length
}
/**
* The current write pointer (the same as {@link length}).
*/
get pos () {
return this.data.length
}
/**
* Create an ArrayBuffer.
*
* @return {Uint8Array} A Uint8Array that represents the written data.
*/
createBuffer () {
return Uint8Array.from(this.data).buffer
}
/**
* Write one byte as an unsigned integer.
*
* @param {number} num The number that is to be encoded.
*/
writeUint8 (num) {
this.data.push(num & bits8)
}
/**
* Write one byte as an unsigned Integer at a specific location.
*
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
setUint8 (pos, num) {
this.data[pos] = num & bits8
}
/**
* Write two bytes as an unsigned integer.
*
* @param {number} num The number that is to be encoded.
*/
writeUint16 (num) {
this.data.push(num & bits8, (num >>> 8) & bits8)
}
/**
* Write two bytes as an unsigned integer at a specific location.
*
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
setUint16 (pos, num) {
this.data[pos] = num & bits8
this.data[pos + 1] = (num >>> 8) & bits8
}
/**
* Write two bytes as an unsigned integer
*
* @param {number} num The number that is to be encoded.
*/
writeUint32 (num) {
for (let i = 0; i < 4; i++) {
this.data.push(num & bits8)
num >>>= 8
}
}
/**
* Write two bytes as an unsigned integer at a specific location.
*
* @param {number} pos The location where the data will be written.
* @param {number} num The number that is to be encoded.
*/
setUint32 (pos, num) {
for (let i = 0; i < 4; i++) {
this.data[pos + i] = num & bits8
num >>>= 8
}
}
/**
* Write a variable length unsigned integer.
*
* @param {number} num The number that is to be encoded.
*/
writeVarUint (num) {
while (num >= 0b10000000) {
this.data.push(0b10000000 | (bits7 & num))
num >>>= 7
}
this.data.push(bits7 & num)
}
/**
* Write a variable length string.
*
* @param {String} str The string that is to be encoded.
*/
writeVarString (str) {
let encodedString = unescape(encodeURIComponent(str))
let bytes = encodedString.split('').map(c => c.codePointAt())
let len = bytes.length
this.writeVarUint(len)
for (let i = 0; i < len; i++) {
this.data.push(bytes[i])
}
}
/**
* Write an ID at the current position.
*
* @param {ID} id The ID that is to be written.
*/
writeID (id) {
const user = id.user
this.writeVarUint(user)
if (user !== RootFakeUserID) {
this.writeVarUint(id.clock)
} else {
this.writeVarString(id.name)
this.writeVarUint(id.type)
}
}
}

View File

@@ -1,7 +1,7 @@
export default class ID {
constructor (user, clock) {
this.user = user
this.user = user // TODO: rename to client
this.clock = clock
}
clone () {

View File

@@ -1,5 +1,5 @@
import ID from '../Util/ID.js'
import ID from '../Util/ID/ID.js.js'
import ItemJSON from '../Struct/ItemJSON.js'
import ItemString from '../Struct/ItemString.js'

View File

@@ -1,4 +1,32 @@
/**
* A SimpleDiff describes a change on a String.
*
* @example
* console.log(a) // the old value
* console.log(b) // the updated value
* // Apply changes of diff (pseudocode)
* a.remove(diff.pos, diff.remove) // Remove `diff.remove` characters
* a.insert(diff.pos, diff.insert) // Insert `diff.insert`
* a === b // values match
*
* @typedef {Object} SimpleDiff
* @property {NaturalNumber} pos The index where changes were applied
* @property {NaturalNumber} delete The number of characters to delete starting
* at `index`.
* @property {String} insert The new text to insert at `index` after applying
* `delete`
*/
/**
* Create a diff between two strings. This diff implementation is intentionally
* not very smart.
*
* @public
* @param {String} a The old version of the string
* @param {String} b The updated version of the string
* @return {SimpleDiff} The diff description.
*/
export default function simpleDiff (a, b) {
let left = 0 // number of same characters counting from left
let right = 0 // number of same characters counting from right
@@ -12,7 +40,7 @@ export default function simpleDiff (a, b) {
}
}
return {
pos: left,
pos: left, // TODO: rename to index (also in type above)
remove: a.length - left - right,
insert: b.slice(left, b.length - right)
}

View File

@@ -1,7 +1,7 @@
import YArray from '../Type/YArray.js'
import YMap from '../Type/YMap.js'
import YText from '../Type/YText.js'
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from '../Type/y-xml/y-xml.js'
import YArray from '../Types/YArray/YArray.js'
import YMap from '../Types/YMap/YMap.js'
import YText from '../Types/YText/YText.js'
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from '../Types/YXml/YXml.js'
import Delete from '../Struct/Delete.js'
import ItemJSON from '../Struct/ItemJSON.js'
@@ -12,7 +12,7 @@ import ItemEmbed from '../Struct/ItemEmbed.js'
const structs = new Map()
const references = new Map()
export function addStruct (reference, structConstructor) {
export function registerStruct (reference, structConstructor) {
structs.set(reference, structConstructor)
references.set(structConstructor, reference)
}
@@ -21,21 +21,21 @@ export function getStruct (reference) {
return structs.get(reference)
}
export function getReference (typeConstructor) {
export function getStructReference (typeConstructor) {
return references.get(typeConstructor)
}
// TODO: reorder (Item* should have low numbers)
addStruct(0, ItemJSON)
addStruct(1, ItemString)
addStruct(10, ItemFormat)
addStruct(11, ItemEmbed)
addStruct(2, Delete)
registerStruct(0, ItemJSON)
registerStruct(1, ItemString)
registerStruct(10, ItemFormat)
registerStruct(11, ItemEmbed)
registerStruct(2, Delete)
addStruct(3, YArray)
addStruct(4, YMap)
addStruct(5, YText)
addStruct(6, YXmlFragment)
addStruct(7, YXmlElement)
addStruct(8, YXmlText)
addStruct(9, YXmlHook)
registerStruct(3, YArray)
registerStruct(4, YMap)
registerStruct(5, YText)
registerStruct(6, YXmlFragment)
registerStruct(7, YXmlElement)
registerStruct(8, YXmlText)
registerStruct(9, YXmlHook)

View File

@@ -1,6 +1,6 @@
import YMap from '../Type/YMap'
import YArray from '../Type/YArray'
import YMap from '../Types/YMap'
import YArray from '../Types/YArray'
export function writeObjectToYMap (object, type) {
for (var key in object) {