Skip to content

Commit

Permalink
Remove CoreMask class (#3)
Browse files Browse the repository at this point in the history
* Remove CoreMask class

* update version

* update docs

* version

* format
  • Loading branch information
Szegoo authored May 7, 2024
1 parent 297bd80 commit 1047074
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 137 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ npm i coretime-utils
Types can be imported directly from the package, e.g.

```js
import { CoreMask } from 'coretime-utils';
import { Region } from 'coretime-utils';
```
56 changes: 34 additions & 22 deletions __tests__/coremask.test.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,63 @@
import { CoreMask, COMPLETE_MASK, VOID_MASK } from '../src';
import {
COMPLETE_MASK,
VOID_MASK,
completeMask,
countMaskOnes,
countMaskZeros,
maskFromBin,
maskFromChunk,
maskToBin,
voidMask,
} from '../src';

describe('CoreMask utils work', () => {
test('constructor works', () => {
expect(() => new CoreMask(COMPLETE_MASK)).not.toThrow();
expect(() => new CoreMask(VOID_MASK)).not.toThrow();
expect(() => new CoreMask('foo')).toThrow();
expect(() => new CoreMask(VOID_MASK + '0')).toThrow();
});

test('fromChunk works', () => {
expect(CoreMask.fromChunk(40, 60).toRawHex()).toEqual('0x0000000000fffff00000');
expect(maskFromChunk(40, 60)).toEqual('0x0000000000fffff00000');
});

test('fromBin works', () => {
expect(
CoreMask.fromBin(
maskFromBin(
'11111111111111111111111111111111111111111111111111111111111111111111111111111111',
).toRawHex(),
),
).toEqual(COMPLETE_MASK);

expect(
CoreMask.fromBin(
maskFromBin(
'00000000000000000000000000000000000000000000000000000000000000000000000000000000',
).toRawHex(),
),
).toEqual(VOID_MASK);
});

test('countOnes works', () => {
expect(CoreMask.voidMask().countOnes()).toEqual(0);
expect(CoreMask.completeMask().countOnes()).toEqual(80);
expect(CoreMask.fromChunk(0, 20).countOnes()).toEqual(20);
const _voidMask = voidMask();
const _completeMask = completeMask();
const _customMask = maskFromChunk(0, 20);
expect(countMaskOnes(_voidMask)).toEqual(0);
expect(countMaskOnes(_completeMask)).toEqual(80);
expect(countMaskOnes(_customMask)).toEqual(20);
});

test('countZeros works', () => {
expect(CoreMask.voidMask().countZeros()).toEqual(80);
expect(CoreMask.completeMask().countZeros()).toEqual(0);
expect(CoreMask.fromChunk(0, 20).countZeros()).toEqual(60);
const _voidMask = voidMask();
const _completeMask = completeMask();
const _customMask = maskFromChunk(0, 20);
expect(countMaskZeros(_voidMask)).toEqual(80);
expect(countMaskZeros(_completeMask)).toEqual(0);
expect(countMaskZeros(_customMask)).toEqual(60);
});

test('toBin works', () => {
expect(CoreMask.voidMask().toBin()).toEqual(
const _voidMask = voidMask();
const _completeMask = completeMask();
const _customMask = maskFromChunk(0, 5);
expect(maskToBin(_voidMask)).toEqual(
'00000000000000000000000000000000000000000000000000000000000000000000000000000000',
);
expect(CoreMask.completeMask().toBin()).toEqual(
expect(maskToBin(_completeMask)).toEqual(
'11111111111111111111111111111111111111111111111111111111111111111111111111111111',
);
expect(CoreMask.fromChunk(0, 5).toBin()).toEqual(
expect(maskToBin(_customMask)).toEqual(
'11111000000000000000000000000000000000000000000000000000000000000000000000000000',
);
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "coretime-utils",
"version": "0.2.8",
"version": "0.3.2",
"description": "An npm package containing types and constants that are commonly reused in regarding Coretime.",
"main": "dist/cjs/index.js",
"types": "dist/cjs/index.d.ts",
Expand Down
114 changes: 46 additions & 68 deletions src/coreMask.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,67 @@
export const VOID_MASK = '0x00000000000000000000'; // hex encoded 80 bit bitmap.
export const COMPLETE_MASK = '0xffffffffffffffffffff'; // hex encoded 80 bit bitmap.

export class CoreMask {
private mask: string;

toRawHex(): string {
return this.mask;
}

constructor(mask: string) {
// 10 hex characters plus the '0x' at the start.
if (isHex(mask) && mask.length === 22) {
this.mask = mask;
} else {
throw new Error('Invalid mask');
}
}
export function completeMask(): string {
return COMPLETE_MASK;
}

static completeMask(): CoreMask {
return new CoreMask(COMPLETE_MASK);
}
export function voidMask(): string {
return VOID_MASK;
}

static voidMask(): CoreMask {
return new CoreMask(VOID_MASK);
export function maskFromChunk(from: number, to: number): string {
if (from < 0 || to >= 80 || from > to) {
throw new Error('Invalid bit range');
}

static fromChunk(from: number, to: number): CoreMask {
if (from < 0 || to >= 80 || from > to) {
throw new Error('Invalid bit range');
}

let mask = 0n;
for (let i = from; i < to; i++) {
mask |= 1n << BigInt(79 - i);
}

return new CoreMask('0x' + mask.toString(16).padStart(20, '0'));
let mask = 0n;
for (let i = from; i < to; i++) {
mask |= 1n << BigInt(79 - i);
}

static fromBin(bin: string): CoreMask {
let hexMask = '';
for (let i = 0; i < bin.length; i += 4) {
const v = parseInt(bin.slice(i, i + 4), 2);
hexMask += v.toString(16);
}
return new CoreMask(`0x${hexMask}`);
}
return '0x' + mask.toString(16).padStart(20, '0');
}

public countZeros(): number {
let count = 0;
for (let i = 2; i < this.mask.length; ++i) {
let v = parseInt(this.mask.slice(i, i + 1), 16);
for (let j = 0; j < 4; ++j) {
if ((v & 1) === 0) ++count;
v >>= 1;
}
export function countMaskZeros(mask: string): number {
let count = 0;
for (let i = 2; i < mask.length; ++i) {
let v = parseInt(mask.slice(i, i + 1), 16);
for (let j = 0; j < 4; ++j) {
if ((v & 1) === 0) ++count;
v >>= 1;
}
return count;
}
return count;
}

public countOnes(): number {
let count = 0;
for (let i = 2; i < this.mask.length; ++i) {
let v = parseInt(this.mask.slice(i, i + 1), 16);
while (v > 0) {
if (v & 1) ++count;
v >>= 1;
}
export function countMaskOnes(mask: string): number {
let count = 0;
for (let i = 2; i < mask.length; ++i) {
let v = parseInt(mask.slice(i, i + 1), 16);
while (v > 0) {
if (v & 1) ++count;
v >>= 1;
}
return count;
}
return count;
}

public toBin(): string {
let bin = '';
for (let i = 2; i < this.mask.length; ++i) {
const v = parseInt(this.mask.slice(i, i + 1), 16);
for (let j = 3; j >= 0; --j) {
bin += v & (1 << j) ? '1' : '0';
}
export function maskToBin(mask: string): string {
let bin = '';
for (let i = 2; i < mask.length; ++i) {
const v = parseInt(mask.slice(i, i + 1), 16);
for (let j = 3; j >= 0; --j) {
bin += v & (1 << j) ? '1' : '0';
}
return bin;
}
return bin;
}

function isHex(str: string) {
const regex = /^0x[0-9a-fA-F]+$/;
return regex.test(str);
export function maskFromBin(bin: string): string {
let hexMask = '';
for (let i = 0; i < bin.length; i += 4) {
const v = parseInt(bin.slice(i, i + 4), 2);
hexMask += v.toString(16);
}
return `0x${hexMask}`;
}
22 changes: 22 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
import { BN } from '@polkadot/util';
import { RawRegionId } from './types';
import { RegionId } from './region';

export * from './coreMask';
export * from './region';
export * from './types';

/**
* Encodes the `regionId` into a BigNumber (BN) format. This is used for interacting
* with the xc-regions contract or when conducting cross-chain transfers, where
* `regionId` needs to be represented as a u128.
*
* @param api The API object used to encode the regionId fields.
* @returns The encoded regionId as a BigNumber (BN)
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getEncodedRegionId(regionId: RegionId, api: any): RawRegionId {
const encodedBegin = api.createType('u32', regionId.begin).toHex().substring(2);
const encodedCore = api.createType('u16', regionId.core).toHex().substring(2);

const rawRegionId = encodedBegin + encodedCore + regionId.mask.substring(2);

return new BN(rawRegionId, 16);
}
51 changes: 6 additions & 45 deletions src/region.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
import {
CoreMask,
CoreIndex,
Timeslice,
Balance,
RawRegionId,
Percentage,
ContextData,
MetadataVersion,
} from '.';
import { BN } from '@polkadot/util';
import { CoreIndex, Timeslice, Balance, Percentage, ContextData, countMaskOnes } from '.';

export type OnChainRegionId = {
// The timeslice at which the region starts.
Expand All @@ -25,7 +15,7 @@ export type RegionId = {
// The index of the relay chain Core on which this Region will be scheduled.
core: CoreIndex;
// The regularity parts in which this Region will be scheduled.
mask: CoreMask;
mask: string;
};

export type RegionRecord = {
Expand All @@ -45,19 +35,16 @@ export enum RegionOrigin {
export class Region {
private regionId: RegionId;
private regionRecord: RegionRecord;
private metadataVersion: MetadataVersion;

/**
* Constructs a new Region instance.
* @param regionId The unique identifier of the region.
* @param regionRecord The record details of the region.
* @param metadataVersion The version of the region metadata.
* In case it is not a xc-region, it should be 0.
*/
constructor(regionId: RegionId, regionRecord: RegionRecord, metadataVersion: MetadataVersion) {
constructor(regionId: RegionId, regionRecord: RegionRecord) {
this.regionId = regionId;
this.regionRecord = regionRecord;
this.metadataVersion = metadataVersion;
}

/**
Expand All @@ -76,7 +63,7 @@ export class Region {
return {
begin: this.getBegin(),
core: this.getCore(),
mask: this.getMask().toRawHex(),
mask: this.getMask(),
};
}

Expand All @@ -88,14 +75,6 @@ export class Region {
return this.regionRecord;
}

/**
* Gets the version of the region metadata.
* @returns If not xc-region this should always be 0.
*/
public getMetadataVersion(): MetadataVersion {
return this.metadataVersion;
}

/**
* Gets the beginning timeslice of the region.
* @returns The starting timeslice.
Expand All @@ -116,7 +95,7 @@ export class Region {
* Gets the mask for the region scheduling.
* @returns The core mask.
*/
public getMask(): CoreMask {
public getMask(): string {
return this.regionId.mask;
}

Expand Down Expand Up @@ -168,24 +147,6 @@ export class Region {
* @returns The percentage of a core's resources that the region 'occupies'
*/
public coreOccupancy(): Percentage {
return this.getMask().countOnes() / 80;
}

/**
* Encodes the `regionId` into a BigNumber (BN) format. This is used for interacting
* with the xc-regions contract or when conducting cross-chain transfers, where
* `regionId` needs to be represented as a u128.
*
* @param api The API object used to encode the regionId fields.
* @returns The encoded regionId as a BigNumber (BN)
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public getEncodedRegionId(api: any): RawRegionId {
const encodedBegin = api.createType('u32', this.regionId.begin).toHex().substring(2);
const encodedCore = api.createType('u16', this.regionId.core).toHex().substring(2);

const rawRegionId = encodedBegin + encodedCore + this.regionId.mask.toRawHex().substring(2);

return new BN(rawRegionId, 16);
return countMaskOnes(this.getMask()) / 80;
}
}

0 comments on commit 1047074

Please sign in to comment.