Skip to content

Commit

Permalink
RAD & Book promoted! + buggy example: test/rad/book.html
Browse files Browse the repository at this point in the history
  • Loading branch information
amark committed Jan 16, 2024
1 parent d7f1947 commit 78a40da
Show file tree
Hide file tree
Showing 6 changed files with 461 additions and 219 deletions.
221 changes: 220 additions & 1 deletion gun.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,231 @@
};
})(USE, './onto');

;USE(function(module){ ;(function(){
// TODO: BUG! Unbuild will make these globals... CHANGE unbuild to wrap files in a function.
// Book is a replacement for JS objects, maps, dictionaries.
var sT = setTimeout, B = sT.Book || (sT.Book = function(text){
var b = function book(word, is){
var has = b.all[word], p;
if(is === undefined){ return (has && has.is) || b.get(has || word) }
if(has){
if(p = has.page){
p.size += size(is) - size(has.is);
p.text = '';
}
has.text = '';
has.is = is;
return b;
}
//b.all[word] = {is: word}; return b;
return b.set(word, is);
};
// TODO: if from text, preserve the separator symbol.
b.list = [{from: text, size: (text||'').length, substring: sub, toString: to, book: b, get: b, read: list}];
b.page = page;
b.set = set;
b.get = get;
b.all = {};
return b;
}), PAGE = 2**12;

function page(word){
var b = this, l = b.list, i = spot(word, l, b.parse), p = l[i];
if('string' == typeof p){ l[i] = p = {size: -1, first: b.parse? b.parse(p) : p, substring: sub, toString: to, book: b, get: b, read: list} } // TODO: test, how do we arrive at this condition again?
//p.i = i;
return p;
// TODO: BUG! What if we get the page, it turns out to be too big & split, we must then RE get the page!
}
function get(word){
if(!word){ return }
if(undefined !== word.is){ return word.is } // JS falsey values!
var b = this, has = b.all[word];
if(has){ return has.is }
// get does an exact match, so we would have found it already, unless parseless page:
var page = b.page(word), l, has, a, i;
if(!page || !page.from){ return } // no parseless data
return got(word, page);
}
function got(word, page){
var b = page.book, l, has, a, i;
if(l = from(page)){ has = l[got.i = i = spot(word, l, B.decode)]; } // TODO: POTENTIAL BUG! This assumes that each word on a page uses the same serializer/formatter/structure.
// parseless may return -1 from actual value, so we may need to test both. // TODO: Double check? I think this is correct.
if(has && word == has.word){ return (b.all[word] = has).is }
if('string' != typeof has){ has = l[got.i = i+=1] }
if(has && word == has.word){ return (b.all[word] = has).is }
a = slot(has) // Escape!
if(word != B.decode(a[0])){
has = l[got.i = i+=1]; // edge case bug?
a = slot(has); // edge case bug?
if(word != B.decode(a[0])){ return }
}
has = l[i] = b.all[word] = {word: ''+word, is: B.decode(a[1]), page: page, substring: subt, toString: tot}; // TODO: convert to a JS value!!! Maybe index! TODO: BUG word needs a page!!!! TODO: Check for other types!!!
return has.is;
}

function spot(word, sorted, parse){ parse = parse || spot.no || (spot.no = function(t){ return t }); // TODO: BUG???? Why is there substring()||0 ? // TODO: PERF!!! .toString() is +33% faster, can we combine it with the export?
var L = sorted, min = 0, page, found, l = (word=''+word).length, max = L.length, i = max/2;
while(((word < (page = (parse(L[i=i>>0])||'').substring())) || ((parse(L[i+1])||'').substring() <= word)) && i != min){ // L[i] <= word < L[i+1]
i += (page <= word)? (max - (min = i))/2 : -((max = i) - min)/2;
}
return i;
}

function from(a, t, l){
if('string' != typeof a.from){ return a.from }
//(l = a.from = (t = a.from||'').substring(1, t.length-1).split(t[0])).toString = join; // slot
(l = a.from = slot(t = t||a.from||'')).toString = join;
return l;
}
function list(each){ each = each || function(x){return x}
// TODO: BUG!!! in limbo items need to get situated before calling this, if there are any. (obviously, we shouldn't do it again if limbo has previously been sorted).
var i = 0, l = from(this)||[], w, r = [], p = this.book.parse || function(){};
while(w = l[i++]){ r.push(each(slot(w)[1],p(w)||w,this)) }
return r;
}

function set(word, is){
var b = this, has = b.all[word];
if(has){ return b(word, is) } // updates to in-memory items will always match exactly.
var page = b.page(word=''+word), tmp; // before we assume this is an insert tho, we need to check
if(page && page.from){ // if it could be an update to an existing word from parseless.
b.get(word);
if(b.all[word]){ return b(word, is) }
}
// MUST be an insert:
has = b.all[word] = {word: word, is: is, page: page, substring: subt, toString: tot};
page.first = (page.first < word)? page.first : word;
if(!page.limbo){ (page.limbo = []).toString = join }
page.limbo.push(has);
b(word, is);
page.size += size(word) + size(is);
if((b.PAGE || PAGE) < page.size){ split(page, b) }
return b;
}

function split(p, b){ // TODO: use closest hash instead of half.
//console.time();
// TODO: BUG???? May need to do a SORTED merge with FROM.
var i = 0, L = p.limbo, tmp;
//while(tmp = L[i++]){ }
var L = p.limbo = sort(p.limbo), l = L.length, i = l/2 >> 0, j = i, half = L[j], tmp;
//console.timeEnd();
var next = {limbo: [], first: half.substring(), size: 0, substring: sub, toString: to, book: b, get: b, read: list}, nl = next.limbo;
nl.toString = join;
//console.time();
while(tmp = L[i++]){
nl.push(tmp);
next.size += (tmp.is||'').length||1;
tmp.page = next;
}
//console.timeEnd();
//console.time();
p.limbo = p.limbo.slice(0, j);
p.size -= next.size;
p.sort = 0;
b.list.splice(spot(next.first, b.list)+1, 0, next); // TODO: BUG! Make sure next.first is decoded text. // TODO: BUG! spot may need parse too?
//console.timeEnd();
if(b.split){ b.split(next, p) }
}

function slot(t){ return heal((t=t||'').substring(1, t.length-1).split(t[0]), t[0]) } B.slot = slot; // TODO: check first=last & pass `s`.
function heal(l, s){ var i, e;
if(0 > (i = l.indexOf(''))){ return l } // ~700M ops/sec on 4KB of Math.random()s, even faster if escape does exist.
if('' == l[0] && 1 == l.length){ return [] } // annoying edge cases! how much does this slow us down?
//if((c=i+2+parseInt(l[i+1])) != c){ return [] } // maybe still faster than below?
if((e=i+2+parseInt((e=l[i+1]).substring(0, e.indexOf('"'))||e)) != e){ return [] } // NaN check in JS is weird.
l[i] = l.slice(i, e).join(s||'|'); // rejoin the escaped value
return l.slice(0,i+1).concat(heal(l.slice(e), s)); // merge left with checked right.
}

function size(t){ return (t||'').length||1 } // bits/numbers less size? Bug or feature?
function subt(i,j){ return this.word }
//function tot(){ return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'" }
function tot(){ var tmp = {};
//if((tmp = this.page) && tmp.saving){ delete tmp.book.all[this.word]; } // TODO: BUG! Book can't know about RAD, this was from RAD, so this MIGHT be correct but we need to refactor. Make sure to add tests that will re-trigger this.
return this.text = this.text || ":"+B.encode(this.word)+":"+B.encode(this.is)+":";
tmp[this.word] = this.is;
return this.text = this.text || B.encode(tmp,'|',':').slice(1,-1);
//return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'";
}
function sub(i,j){ return (this.first||this.word||B.decode((from(this)||'')[0]||'')).substring(i,j) }
function to(){ return this.text = this.text || text(this) }
function join(){ return this.join('|') }
function text(p){ var l = p.limbo; // TODO: BUG??? Shouldn't any stringify cause limbo to be reset?
if(!l){ return (typeof p.from == 'string')? (p.from||'')+'' : '|'+p.from+'|' }
if(!p.from){ return p.limbo = null, '|'+((l && sort(l).join('|'))||'')+'|' } // TODO: p.limbo should be reset each time we "flush".
return '|'+mix(l, from(p), p).join('|')+'|'; // commenting out this sub-portion of code fixed a more basic test, but will probably cause a bug with a FROM + MEMORY.
}
function mix(l, f, p){ // TODO: IMPROVE PERFORMANCE!!!! l[j] = i is 5X+ faster than .push(
var j = 0, i;
while(i = l[j++]){
if(got(i.word, p)){
f[got.i] = i;
} else {
f.push(i);
}
}
return sort(f);
}
function sort(l){ //return l.sort();
return l.sort(function(a,b){
return (a.word||B.decode(''+a)) < (b.word||B.decode(''+b))? -1:1;
});
}

B.encode = function(d, s, u){ s = s || "|"; u = u || String.fromCharCode(32);
switch(typeof d){
case 'string': // text
var i = d.indexOf(s), c = 0;
while(i != -1){ c++; i = d.indexOf(s, i+1) }
return (c?s+c:'')+ '"' + d;
case 'number': return (d < 0)? ''+d : '+'+d;
case 'boolean': return d? '+' : '-';
case 'object': if(!d){ return ' ' } // TODO: BUG!!! Nested objects don't slot correctly
var l = Object.keys(d).sort(), i = 0, t = s, k, v;
while(k = l[i++]){ t += u+B.encode(k,s,u)+u+B.encode(d[k],s,u)+u+s }
return t;
}
}
B.decode = function(t, s){ s = s || "|";
if('string' != typeof t){ return }
switch(t){ case ' ': return null; case '-': return false; case '+': return true; }
switch(t[0]){
case '-': case '+': return parseFloat(t);
case '"': return t.slice(1);
}
return t.slice(t.indexOf('"')+1);
}

B.hash = function(s, c){ // via SO
if(typeof s !== 'string'){ return }
c = c || 0; // CPU schedule hashing by
if(!s.length){ return c }
for(var i=0,l=s.length,n; i<l; ++i){
n = s.charCodeAt(i);
c = ((c<<5)-c)+n;
c |= 0;
}
return c;
}

function record(key, val){ return key+B.encode(val)+"%"+key.length }
function decord(t){
var o = {}, i = t.lastIndexOf("%"), c = parseFloat(t.slice(i+1));
o[t.slice(0,c)] = B.decode(t.slice(c,i));
return o;
}

try{module.exports=B}catch(e){}
}());//delete later.
})(USE, './book');

;USE(function(module){
// Valid values are a subset of JSON: null, binary, number (!Infinity), text,
// or a soul relation. Arrays need special algorithms to handle concurrency,
// so they are not supported directly. Use an extension that supports them if
// needed but research their problems first.
module.exports = function (v) {
module.exports = function(v){
// "deletes", nulling out keys.
return v === null ||
"string" === typeof v ||
Expand Down
Loading

0 comments on commit 78a40da

Please sign in to comment.