Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oblivious LRU with delete -- addressed pull request comments, added LRUMapWithDelete #173

Merged
merged 5 commits into from
Nov 19, 2021

Conversation

mrflip
Copy link
Contributor

@mrflip mrflip commented Nov 17, 2021

This PR is all to the credit of @trivikr's PR #162 ; in order to help accelerate its inclusion in the proper release I've added commits that address the PR comments, and also added LRUMapWithDelete using the analogous strategy.

It wasn't clear to me what ObliviousLRUCache meant -- perhaps it's a term of art I haven't met yet -- but I took the liberty of renaming it to the homely but very clear LRUCacheWithDelete / LRUMapWithDelete. (Also, putting the adjective last grouped them together in the tests / indexes / etc where things are alphabetized). I'm glad to redo the commit history if ObliviousLRUCache is the proper name for this widget.

Last point -- in the comments on 162 @Yomguithereal recommended "a rolling test ... add 2 remove 1, in a loop of ~10 items for a cache of ~4-5 capacity." I tried to think of a way to give it a workout with a nice clean loop and still test it meaningfully -- like a fizzbuzz kind of thing -- but bringing in a pattern seemed too artificial and I think there'd be a lot of logic lying around. Instead, I just spammed in a whole bunch of inserts and deletes and asserted the state of the cache at various rest stops. To my mind this proved the same point that a loop would but more clearly demonstrated there was nothing up my sleeve mathematically. Does this do the trick for you?

@mrflip
Copy link
Contributor Author

mrflip commented Nov 17, 2021

One other change from 162 -- at the cost of one extra array reference op, the delete method returns the dead item. If that cost is meaningful I can add a ¿deletePop? method to parallel set / setPop.

// list of "holes" in the pointer array. On insert, if there is a hole
// the new pointer slots in to fill the hole; otherwise, it is
// appended as usual. (Note: we are only talking here about the
// internal pointer list. set'ing or get'ing an item promotes it
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo on set'ing and get'ing.

}

LRUCacheWithDelete.prototype = Object.create(LRUCache.prototype);
LRUCacheWithDelete.prototype.constructor = LRUCacheWithDelete;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure but I think .constructor is not enumerable, which means that the following:

for (var k in LRUCache.prototype)
  LRUCacheWithDelete.prototype[k] = LRUCache.prototype[k];

would to the trick less "magically"?

* @return {undefined}
*/
LRUCacheWithDelete.prototype.set = function(key, value) {
this.setpop(key, value);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can bench using a proper #.set vs. relying on #.setpop internally this could be useful because I have a, maybe false, intuition that the need to create the object to return costs you a little performance and this method has to be performance-critical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if I benched it fine on say Node, I wouldn't trust that to extend to whatever browsers. I propose to un-DRY it as you did for the parent class.

return undefined;
}

const dead = this.V[pointer];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any issue with this particularly, and I don't think the array deref is such a perf hit but I notice that the equivalent in, say, an ES6 map, is to return a boolean on delete. I agree it looks more useful to return the value even though you won't be able to distinguish between an actual deletion or else if you use undefined as values (but if you do so, who are you? why are you doing this :) ?).

Copy link
Contributor Author

@mrflip mrflip Nov 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless the repetition bothers you, I'll update my proposal to add the "returns its dead" method as remove, along with a delete method that returns a boolean. (edited -- my first response wouldn't have worked)

@Yomguithereal
Copy link
Owner

Thanks for your PR @mrflip. I have opened a small review with some comments. The unit tests look good to me.

* un-DRY'ed set to match lru-map / lru-cache
* made #delete return boolean (true if entry was present)
* added #remove, which deletes item and returns its former value
@mrflip
Copy link
Contributor Author

mrflip commented Nov 18, 2021

Pushed a new commit addressing your comments. Remove lets you supply a singleton -- eg Symbol('missing') -- to indicate absence, permitting one to have undefined be in range.

@Yomguithereal
Copy link
Owner

Looks good to me @mrflip. I am trying to find a less conspicuous name for the structure but I don't suceed, so I guess explicit is nice. @trivikr any remark before I merge and release?

@Yomguithereal Yomguithereal merged commit 131da44 into Yomguithereal:master Nov 19, 2021
@Yomguithereal
Copy link
Owner

I merged the PR just now. Will release a new version in the evening I think (I need to batch up some SparseSet improvements along with it).

@Yomguithereal
Copy link
Owner

v0.39 is now live

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants