From 6826d32ca70ec6b6e751813bb595b6ade288cb69 Mon Sep 17 00:00:00 2001 From: sanine-a Date: Tue, 23 May 2023 13:36:35 -0500 Subject: add random non-overlapping ranges in core --- src/vm/core.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/vm/core.test.js | 42 +++++++++++++++++++++++++++++++ src/vm/vm.js | 36 +++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 src/vm/core.test.js create mode 100644 src/vm/vm.js diff --git a/src/vm/core.js b/src/vm/core.js index 4fdd0a0..184be00 100644 --- a/src/vm/core.js +++ b/src/vm/core.js @@ -3,6 +3,46 @@ const { Op, AddrMode} = require('./enum.js'); +function mod(a, N) { + const A = a % N; + if (A < 0) { + return A + N; + } else { + return A; + } +} + + +class Range { + constructor(start, end, coresize) { + this.start = start; + this.end = end; + this.coresize = coresize; + } + + + // thanks to https://fgiesen.wordpress.com/2015/09/24/intervals-in-modular-arithmetic/ + // c: + contains(n) { + return mod(n - this.start, this.coresize) <= mod(this.end - this.start, this.coresize); + } + + overlaps(other) { + return ( + this.contains(other.start) || + other.contains(this.start) + ); + } +} + + +function randomRange(coresize, length) { + const start = Math.floor(Math.random() * coresize); + const end = mod(start + length - 1, coresize); + return new Range(start, end, coresize); +} + + class Core { constructor(size) { this.data = new Array(size); @@ -18,13 +58,31 @@ class Core { } - normalize(pc, value) { - const v = (pc + value) % this.data.length; - if (v < 0) { - return v + this.data.length; - } else { - return v; + getRanges(lengths, ranges) { + if (ranges === undefined) { + ranges = []; + } + + if (lengths.length === 0) { + return ranges; } + + const length = lengths[0]; + let range; + do { + range = randomRange(this.data.length, length); + } while ( + ranges + .map(r => r.overlaps(range)) + .reduce((acc, overlap) => acc || overlap, false) + ); + + return this.getRanges(lengths.slice(1), [...ranges, range]); + } + + + normalize(pc, value) { + return mod((pc + value), this.data.length); } @@ -57,4 +115,6 @@ class Core { } +exports.mod = mod; +exports.Range = Range; exports.Core = Core; diff --git a/src/vm/core.test.js b/src/vm/core.test.js new file mode 100644 index 0000000..84aab6f --- /dev/null +++ b/src/vm/core.test.js @@ -0,0 +1,42 @@ +'use strict'; + +const { mod, Range, Core } = require('./core.js'); + +test('ranges overlap correctly', () => { + const a = new Range(7, 1, 8); + const b = new Range(0, 2, 8); + const c = new Range(3, 5, 8); + + expect(a.overlaps(a)).toBe(true); + expect(b.overlaps(b)).toBe(true); + expect(c.overlaps(c)).toBe(true); + + expect(a.overlaps(b)).toBe(true); + expect(b.overlaps(a)).toBe(true); + expect(a.overlaps(c)).toBe(false); + expect(b.overlaps(c)).toBe(false); + expect(c.overlaps(a)).toBe(false); + expect(c.overlaps(b)).toBe(false); +}); + +test('get non-overlapping ranges in a core', () => { + const CORESIZE = 8000; + const core = new Core(CORESIZE); + + for (let loop=0; loop<500; loop++) { + const ranges = core.getRanges([20, 10, 5, 5]); + + expect(ranges.length).toBe(4); + expect(mod(ranges[0].end - ranges[0].start + 1, CORESIZE)).toBe(20); + expect(mod(ranges[1].end - ranges[1].start + 1, CORESIZE)).toBe(10); + expect(mod(ranges[2].end - ranges[2].start + 1, CORESIZE)).toBe(5); + expect(mod(ranges[3].end - ranges[3].start + 1, CORESIZE)).toBe(5); + + for (let i=0; i