Skip to content

Commit d5d6e01

Browse files
committed
Support objects when cmp(a, b) === 0 but a !== b
[closes #10]
1 parent 11cffee commit d5d6e01

File tree

5 files changed

+70
-55
lines changed

5 files changed

+70
-55
lines changed

src/SortedSet/AbstractBinaryTreeStrategy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class AbstractBinaryTree {
4545
node = node.right;
4646
}
4747
}
48-
return node !== null && node.value === value;
48+
return node !== null && comparator(node.value, value) === 0;
4949
}
5050

5151
findIterator(value) {

src/SortedSet/ArrayStrategy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class ArrayStrategy {
8787

8888
remove(value) {
8989
const index = binarySearchForIndex(this.data, value, this.comparator);
90-
if (this.data[index] !== value) {
90+
if (this.comparator(this.data[index], value) !== 0) {
9191
throw 'Value not in set';
9292
}
9393
return this.data.splice(index, 1);
@@ -99,7 +99,7 @@ class ArrayStrategy {
9999

100100
contains(value) {
101101
const index = binarySearchForIndex(this.data, value, this.comparator);
102-
return this.index !== this.data.length && this.data[index] === value;
102+
return this.index !== this.data.length && this.comparator(this.data[index], value) === 0;
103103
}
104104

105105
forEachImpl(callback, sortedSet, thisArg) {

src/SortedSet/BinaryTreeStrategy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class BinaryTreeStrategy extends AbstractBinaryTreeStrategy {
5252

5353
insert(value) {
5454
const compare = this.comparator;
55-
if (this.root != null) {
55+
if (this.root !== null) {
5656
let parent = this.root;
5757
let leftOrRight = null;
5858
while (true) {

src/SortedSet/RedBlackTreeStrategy.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ const removeFromNode = (h, value, compare) => {
132132
if (h === null) {
133133
throw 'Value not in set';
134134
}
135-
if (h.value !== value && compare(value, h.value) < 0) {
135+
if (compare(value, h.value) < 0) {
136136
if (h.left === null) {
137137
throw 'Value not in set';
138138
}
@@ -145,7 +145,7 @@ const removeFromNode = (h, value, compare) => {
145145
h = rotateRight(h);
146146
}
147147
if (h.right === null) {
148-
if (value === h.value) {
148+
if (compare(value, h.value) === 0) {
149149
return null; // leaf node; LLRB assures no left value here
150150
} else {
151151
throw 'Value not in set';
@@ -154,7 +154,7 @@ const removeFromNode = (h, value, compare) => {
154154
if (!h.right.isRed && !(h.right.left !== null && h.right.left.isRed)) {
155155
h = moveRedRight(h);
156156
}
157-
if (value === h.value) {
157+
if (compare(value, h.value) === 0) {
158158
h.value = findMinNode(h.right).value;
159159
h.right = removeMinNode(h.right);
160160
} else {

test/helpers/StrategyHelper.js

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const describeStrategy = (description, strategy) => {
5959
expect(callback).not.to.have.been.called
6060
})
6161
})
62+
6263
describe('with some numbers', function () {
6364
beforeEach(function () {
6465
priv = new strategy({
@@ -212,6 +213,56 @@ const describeStrategy = (description, strategy) => {
212213
})
213214
})
214215

216+
describe('with objects for which cmp(a, b) === 0 and a !== b', function () {
217+
beforeEach(function () {
218+
priv = new strategy({
219+
comparator: (a, b) => a.id - b.id
220+
})
221+
// Insert in this order so binary tree isn't one-sided
222+
priv.insert({ id: 2 })
223+
priv.insert({ id: 1 })
224+
priv.insert({ id: 3 })
225+
})
226+
227+
it('should insert in the middle', function () {
228+
priv.insert({ id: 2.5 })
229+
expect(priv.toArray()).to.deep.eq([{ id: 1 }, { id: 2 }, { id: 2.5 }, { id: 3 }])
230+
})
231+
232+
it('should remove from the beginning', function () {
233+
priv.remove({ id: 1 })
234+
expect(priv.toArray()).to.deep.eq([{ id: 2 }, { id: 3 }])
235+
})
236+
237+
it('should remove from the end', function () {
238+
priv.remove({ id: 3 })
239+
expect(priv.toArray()).to.deep.eq([{ id: 1 }, { id: 2 }])
240+
})
241+
242+
it('should remove from the middle', function () {
243+
priv.remove({ id: 2 })
244+
expect(priv.toArray()).to.deep.eq([{ id: 1 }, { id: 3 }])
245+
})
246+
247+
it('should contain a middle value', function () {
248+
expect(priv.contains({ id: 2 })).to.eq(true)
249+
})
250+
251+
it('should not contain a value in between two values', function () {
252+
expect(priv.contains({ id: 1.5 })).to.eq(false)
253+
})
254+
255+
it('should find an iterator', function () {
256+
const iterator = priv.findIterator({ id: 2 })
257+
expect(iterator.value()).to.deep.eq({ id: 2 })
258+
})
259+
260+
it('should find an iterator between values', function () {
261+
const iterator = priv.findIterator({ id: 1.5 })
262+
expect(iterator.value()).to.deep.eq({ id: 2 })
263+
})
264+
})
265+
215266
describe('with allowSetValue', function () {
216267
beforeEach(function () {
217268
priv = new strategy({
@@ -243,14 +294,8 @@ const describeStrategy = (description, strategy) => {
243294
}
244295
const onInsertConflict = SortedSet.OnInsertConflictThrow
245296
priv = new strategy({ comparator, onInsertConflict })
246-
priv.insert({
247-
v: 1,
248-
q: 'a'
249-
})
250-
priv.insert({
251-
v: 2,
252-
q: 'b'
253-
})
297+
priv.insert({ v: 1, q: 'a' })
298+
priv.insert({ v: 2, q: 'b' })
254299
})
255300

256301
it('should throw when inserting an element that matches another', function () {
@@ -266,30 +311,15 @@ const describeStrategy = (description, strategy) => {
266311
}
267312
onInsertConflict = SortedSet.OnInsertConflictReplace
268313
priv = new strategy({ comparator, onInsertConflict })
269-
priv.insert({
270-
v: 1,
271-
q: 'a'
272-
})
273-
priv.insert({
274-
v: 2,
275-
q: 'b'
276-
})
314+
priv.insert({ v: 1, q: 'a' })
315+
priv.insert({ v: 2, q: 'b' })
277316
})
278317

279318
it('should replace a matching element with the new element', function () {
280-
priv.insert({
281-
v: 1,
282-
q: 'c'
283-
})
319+
priv.insert({ v: 1, q: 'c' })
284320
expect(priv.toArray()).to.deep.eq([
285-
{
286-
v: 1,
287-
q: 'c'
288-
},
289-
{
290-
v: 2,
291-
q: 'b'
292-
}
321+
{ v: 1, q: 'c' },
322+
{ v: 2, q: 'b' }
293323
])
294324
})
295325
})
@@ -301,30 +331,15 @@ const describeStrategy = (description, strategy) => {
301331
}
302332
const onInsertConflict = SortedSet.OnInsertConflictIgnore
303333
priv = new strategy({ comparator, onInsertConflict })
304-
priv.insert({
305-
v: 1,
306-
q: 'a'
307-
})
308-
priv.insert({
309-
v: 2,
310-
q: 'b'
311-
})
334+
priv.insert({ v: 1, q: 'a' })
335+
priv.insert({ v: 2, q: 'b' })
312336
})
313337

314338
it('should ignore the new element when inserting an element that matches another ', function () {
315-
priv.insert({
316-
v: 1,
317-
q: 'c'
318-
})
339+
priv.insert({ v: 1, q: 'c' })
319340
expect(priv.toArray()).to.deep.eq([
320-
{
321-
v: 1,
322-
q: 'a'
323-
},
324-
{
325-
v: 2,
326-
q: 'b'
327-
}
341+
{ v: 1, q: 'a' },
342+
{ v: 2, q: 'b' }
328343
])
329344
})
330345
})

0 commit comments

Comments
 (0)