cos/memory.js

668 lines
17 KiB
JavaScript
Raw Normal View History

2024-10-25 23:33:29 +03:00
class ProcessableData {
2024-10-26 19:13:22 +03:00
/**
* @param {Uint8Array} data
* @param {number} from
* @param {number} to
*/
2024-10-25 23:33:29 +03:00
constructor(data, from = 0, to){
2024-10-26 19:13:22 +03:00
if(data)
{
if(data instanceof ArrayBuffer)
{
this.data = new Uint8Array(data);
}else if(data instanceof Uint8Array)
{
this.data = data;
}else if(typeof data == "number")
{
this.data = new Uint8Array(data);
}else{
throw new Error("data is not type ArrayBuffer or Uint8Array");
}
2024-10-25 23:33:29 +03:00
this.init(from, to);
}
}
/** @type {Uint8Array} */
data = null;
/** @type {DataView} */
dt = null;
/** @type {number} */
cursor = 0;
/**
* @param {number} from
* @param {number} to
*/
init(from, to){
if(this.data == null)
{
this.data = new Uint8Array(1024 * 1024);
}
this.dt = new DataView(this.data.buffer, from, to);
}
/** @param {number} value */
writeUInt8(value){
this.dt.setUint8(this.cursor,value);
this.cursor += 1;
}
/** @param {number} value */
writeUInt16(value){
this.dt.setUint16(this.cursor,value);
this.cursor += 2;
}
/** @param {number} value */
writeUInt32(value){
this.dt.setUint32(this.cursor,value);
this.cursor += 4;
}
/** @param {number} value */
writeInt8(value){
this.dt.setInt8(this.cursor,value);
this.cursor += 1;
}
/** @param {number} value */
writeInt16(value){
this.dt.setInt16(this.cursor,value);
this.cursor += 2;
}
/** @param {number} value */
writeInt32(value){
this.dt.setInt32(this.cursor,value);
this.cursor += 4;
}
/** @param {number} value */
writeFloat32(value){
this.dt.setFloat32(this.cursor,value);
this.cursor += 4;
}
/** @param {number} value */
writeFloat64(value){
this.dt.setFloat64(this.cursor,value);
this.cursor += 8;
}
/** @returns {number} */
readUInt8(){
let value = this.dt.getUint8(this.cursor);
this.cursor += 1;
return value;
}
/** @returns {number} */
readUInt16(){
let value = this.dt.getUint16(this.cursor);
this.cursor += 2;
return value;
}
/** @returns {number} */
readUInt32(){
let value = this.dt.getUint32(this.cursor);
this.cursor += 4;
return value;
}
/** @returns {number} */
readInt8(){
let value = this.dt.getInt8(this.cursor);
this.cursor += 1;
return value;
}
/** @returns {number} */
readInt16(){
let value = this.dt.getInt16(this.cursor);
this.cursor += 2;
return value;
}
/** @returns {number} */
readInt32(){
let value = this.dt.getInt32(this.cursor);
this.cursor += 4;
return value;
}
/** @returns {number} */
readFloat32(){
let value = this.dt.getFloat32(this.cursor);
this.cursor += 4;
return value;
}
/** @returns {number} */
readFloat64(){
let value = this.dt.getFloat64(this.cursor);
this.cursor += 8;
return value;
}
getAllData(){
return this.dt.buffer.slice(0, this.cursor);
}
}
class ConstructedData extends ProcessableData {
/** @param {string} value */
writeString(value){
let encodedText = new TextEncoder().encode(value);
for (const byte of encodedText)
{
this.writeUInt8(byte);
}
}
/**
* @param {number} value
* @returns {string}
*/
readString(size){
let minibuffer = this.data.buffer.slice(this.cursor, this.cursor + size);
2024-10-26 18:11:11 +03:00
this.cursor += size;
2024-10-25 23:33:29 +03:00
return new TextDecoder().decode(minibuffer);
}
/**
* @param {boolean|0|1} flag1
* @param {boolean|0|1} flag2
* @param {boolean|0|1} flag3
* @param {boolean|0|1} flag4
* @param {boolean|0|1} flag5
* @param {boolean|0|1} flag6
* @param {boolean|0|1} flag7
* @param {boolean|0|1} flag8
*/
writeFlags(flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8){
let value = (
2024-10-26 18:11:11 +03:00
(flag1 << 0) |
(flag2 << 1) |
(flag3 << 2) |
(flag4 << 3) |
(flag5 << 4) |
(flag6 << 5) |
(flag7 << 6) |
(flag8 << 7)
2024-10-25 23:33:29 +03:00
);
this.writeUInt8(value);
}
/** @returns {number[]} */
readFlags(){
let value = this.readUInt8();
2024-10-26 18:11:11 +03:00
let result = [
2024-10-25 23:33:29 +03:00
(value >> 0 & 0x1),
(value >> 1 & 0x1),
(value >> 2 & 0x1),
(value >> 3 & 0x1),
(value >> 4 & 0x1),
(value >> 5 & 0x1),
(value >> 6 & 0x1),
(value >> 7 & 0x1)
2024-10-26 18:11:11 +03:00
];
2024-10-25 23:33:29 +03:00
return result;
}
/**
* @param {number} r
* @param {number} g
* @param {number} b
*/
writeRGB(r,g,b){
this.writeUInt8(r);
this.writeUInt8(g);
this.writeUInt8(b);
}
/** @returns {{r:number,g:number,b:number}} */
readRGB(){
return {
r: this.readUInt8(),
g: this.readUInt8(),
b: this.readUInt8()
}
}
/**
* @param {number} r
* @param {number} g
* @param {number} b
*/
writeRGBA(r,g,b,a){
this.writeUInt8(r);
this.writeUInt8(g);
this.writeUInt8(b);
this.writeUInt8(a);
}
/** @returns {{r:number,g:number,b:number,a:number}} */
readRGBA(){
return {
r: this.readUInt8(),
g: this.readUInt8(),
b: this.readUInt8(),
a: this.readUInt8()
}
}
/** @param {number} size */
writeVarNumber(size){
let iszero = false;
let isInt = Number.isInteger(size);
let is1Byte = false;
let is2Byte = false;
let is4Byte = false;
let is8Byte = false;
let issigned = false;
issigned = size < 0;
if(isInt){
if(size === 0)
{
iszero = true;
}else if(size >= 0 && size <= 255)
{
is1Byte = true;
}else if(size >= -127 && size <= 127)
{
is1Byte = true;
}else if(size >= -32768 && size <= 32767)
{
is2Byte = true;
}else if(size >= -2147483648 && size <= 2147483647)
{
is4Byte = true;
}
}else {
if(size >= -3.4028235e38 && size <= 3.4028235e38)
{
is4Byte = true;
}else {
is8Byte = true;
}
};
this.writeFlags(
iszero,
isInt,
is1Byte,
is2Byte,
is4Byte,
is8Byte,
issigned,
2024-10-26 19:13:22 +03:00
0
2024-10-25 23:33:29 +03:00
);
if(isInt == false)
{
if(is4Byte)
{
this.writeFloat32(size);
}
if(is8Byte)
{
this.writeFloat64(size);
}
}else{
if(is1Byte)
{
if(issigned)
{
this.writeInt16(size);
}else{
this.writeUInt8(size);
}
}
if(is2Byte)
{
if(issigned)
{
this.writeInt32(size);
}else{
this.writeUInt16(size);
}
}
if(is4Byte)
{
if(issigned)
{
this.writeInt32(size);
}else{
this.writeUInt32(size);
}
}
}
}
/** @returns {number} */
readVarNumber(){
let [
iszero,
isInt,
is1Byte,
is2Byte,
is4Byte,
is8Byte,
issigned
] = this.readFlags();
if(iszero)
{
return 0;
}
if(!isInt)
{
if(is4Byte)
{
return this.readFloat32(); // 32-bit float
}else if(is8Byte)
{
return this.readFloat64(); // 64-bit float
}
}else {
if(is1Byte)
{
if(issigned)
{
return this.readInt8();
}else
{
return this.readUInt8();
}
}else if(is2Byte)
{
if(issigned)
{
return this.readInt16();
}else {
return this.readUInt16();
}
}else if(is4Byte)
{
if(issigned)
{
return this.readInt32();
}else {
return this.readUInt32();
}
}
}
}
/** @param {Date|string} dateorString */
2024-10-26 18:11:11 +03:00
writeTime(dateorString){
2024-10-25 23:33:29 +03:00
let date = new Date(dateorString);
this.writeUInt32(+date);
}
/** @returns {Date} */
2024-10-26 18:11:11 +03:00
readTime(){
2024-10-25 23:33:29 +03:00
return new Date(this.readUInt32());
}
2024-10-26 18:11:11 +03:00
};
class DataAnchor extends ConstructedData {
/**
* @param {string|number} name
* @returns {{read:Function,write:Function,sign:number,name:string,primitive:boolean}}
*/
getProcessor(name)
{
switch(name)
{
case "uint8":
case "byte":
case 1: return {
read : () => this.readUInt8(),
write : value => this.writeUInt8(value),
sign: 1,
name: "uint8",
primitive: true
}
case "uint16":
case 2: return {
read : () => this.readUInt16(),
write : value => this.writeUInt16(value),
sign: 2,
name: "uint16",
primitive: true
}
case "uint32":
case 3: return {
read : () => this.readUInt32(),
write : value => this.writeUInt32(value),
sign: 3,
name: "uint32",
primitive: true
}
case "int8":
case 4: return {
read : () => this.readInt8(),
write : value => this.writeInt8(value),
sign: 4,
name: "int8",
primitive: true
}
case "int16":
case 5: return {
read : () => this.readInt16(),
write : value => this.writeInt16(value),
sign: 5,
name: "int16",
primitive: true
}
case "int32":
case 6: return {
read : () => this.readInt32(),
write : value => this.writeInt32(value),
sign: 6,
name: "int32",
primitive: true
}
case "float32":
case 7: return {
read : () => this.readFloat32(),
write : value => this.writeFloat32(value),
sign: 7,
name: "float32",
primitive: true
}
case "float64":
case 8: return {
read : () => this.readFloat64(),
write : value => this.writeFloat64(value),
sign: 8,
name: "float64",
primitive: true
}
case "string":
case 9: return {
read : size => this.readString(size),
write : value => this.writeString(value),
sign: 9,
name: "string",
primitive: false
}
case "rgb":
case 10: return {
read : () => this.readRGB(),
write : value => this.writeRGB(value),
sign: 10,
name: "rgb",
primitive: true
}
case "rgba":
case 11: return {
read : () => this.readRGBA(),
write : value => this.writeRGBA(value),
sign: 11,
name: "rgba",
primitive: true
}
case "varnumber":
case 12: return {
read : () => this.readVarNumber(),
write : value => this.writeVarNumber(value),
sign: 12,
name: "varnumber",
primitive: true
}
case "time":
case 13: return {
read : () => this.readTime(),
write : value => this.writeTime(value),
sign: 13,
name: "time",
primitive: true
}
};
}
}
class DataStructure {
2024-10-26 19:13:22 +03:00
constructor(structure){
if(typeof structure == "string")
{
this.setHeadSigner(structure);
}
}
2024-10-26 18:11:11 +03:00
/** @type {boolean} */
sign = true;
/** @type {string} */
type = "uint8";
/** @type {boolean} */
list = true;
/** @type {boolean} */
fixedLength = true;
/** @type {any} */
value = null;
size = 1;
2024-10-26 19:13:22 +03:00
reset(){
this.size = 1;
this.fixedLength = true;
this.list = true;
this.type = "uint8";
this.sign = true;
}
2024-10-26 18:11:11 +03:00
/** @param {DataAnchor} da */
setData(da){
let dataCost = da.getProcessor(this.type);
if(this.sign == true)
{
// Verinin içine veri türüni işliyor
da.writeUInt8(dataCost.sign);
}
if(this.fixedLength == false && this.list == true)
{
// Eğer sabit uzunlukta değilse ne kadar uzun olduğunu bildirmeli
da.writeVarNumber(this.size)
}
if(dataCost.primitive)
{
if(this.list == true)
{
for (const data of this.value)
{
dataCost.write(data);
}
}else{
dataCost.write(this.value);
}
}else{
if(this.list == true)
{
for (const data of this.value)
{
da.writeVarNumber(data.length);
dataCost.write(data);
}
}else{
da.writeVarNumber(this.value.length);
dataCost.write(this.value);
}
}
}
/** @param {DataAnchor} da */
getData(da){
2024-10-26 19:13:22 +03:00
let result = null;
2024-10-26 18:11:11 +03:00
if(this.sign == true)
{
// Verinin içine veri türüni işliyor
2024-10-26 19:13:22 +03:00
this.type = da.readUInt8();
2024-10-26 18:11:11 +03:00
}
let dataCost = da.getProcessor(this.type);
if(this.fixedLength == false && this.list == true)
{
// Eğer sabit uzunlukta değilse ne kadar uzun olduğunu bildirmeli
this.size = da.readVarNumber();
}
if(dataCost.primitive)
{
if(this.list == true)
{
result = [];
2024-10-26 19:13:22 +03:00
for (let t = 0;t < this.size; t++)
2024-10-26 18:11:11 +03:00
{
result.push(dataCost.read());
}
}else{
result = dataCost.read();
}
}else{
if(this.list == true)
{
result = [];
2024-10-26 19:13:22 +03:00
for (let t = 0;t < this.size; t++)
2024-10-26 18:11:11 +03:00
{
2024-10-26 19:13:22 +03:00
let length = da.readVarNumber();
2024-10-26 18:11:11 +03:00
result.push(dataCost.read(length));
}
}else{
2024-10-26 19:13:22 +03:00
let length = da.readVarNumber();
2024-10-26 18:11:11 +03:00
result = dataCost.read(length);
}
}
return result;
}
/** @param {string} dataSigner */
setHeadSigner(dataSigner){
2024-10-26 19:13:22 +03:00
let regex = /^(\w+)(\?)(\[\d*\])?$/.exec(dataSigner);
2024-10-26 18:11:11 +03:00
2024-10-26 19:13:22 +03:00
if(regex[1] != 'any')
{
this.type = regex[1];
}
if(regex[2] == '?')
2024-10-26 18:11:11 +03:00
{
this.sign = true;
}else{
this.sign = false;
}
2024-10-26 19:13:22 +03:00
if(regex[3])
2024-10-26 18:11:11 +03:00
{
this.list = true;
2024-10-26 19:13:22 +03:00
this.fixedLength = regex[3] != '[]'
this.size = regex[3].slice(1,-1) | 0;
2024-10-26 18:11:11 +03:00
}else{
this.list = false;
}
}
2024-10-26 19:13:22 +03:00
getHeadSigner(){
let t = [];
if(this.sign)
{
t.push('any')
}else{
t.push(this.type)
}
if(this.list)
{
if(this.fixedLength == false)
{
t.push('[]')
}else{
t.push('[', this.size,']')
}
}
return t.join('')
}
static ds = new DataStructure();
/**
* @param {string} sign
*/
static settle(da, sign, value, size)
{
this.ds.setHeadSigner(sign);
this.ds.value = value;
typeof size == "number" && (this.ds.size = size);
this.ds.setData(da);
this.ds.reset();
}
static gettle(da, sign)
{
this.ds.setHeadSigner(sign);
return this.ds.getData(da);
}
}