mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-08 16:28:49 +00:00
binarySearch and improve insertEventInto___List() to use that and .splice()
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { describe, test, expect } from 'bun:test'
|
import { describe, test, expect } from 'bun:test'
|
||||||
import { buildEvent } from './test-helpers.ts'
|
import { buildEvent } from './test-helpers.ts'
|
||||||
import { Queue, insertEventIntoAscendingList, insertEventIntoDescendingList } from './utils.ts'
|
import { Queue, insertEventIntoAscendingList, insertEventIntoDescendingList, binarySearch } from './utils.ts'
|
||||||
|
|
||||||
import type { Event } from './event.ts'
|
import type { Event } from './event.ts'
|
||||||
|
|
||||||
@@ -214,13 +214,13 @@ describe('inserting into a asc sorted list of events', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('enque a message into MessageQueue', () => {
|
describe('enqueue a message into MessageQueue', () => {
|
||||||
test('enque into an empty queue', () => {
|
test('enqueue into an empty queue', () => {
|
||||||
const queue = new Queue()
|
const queue = new Queue()
|
||||||
queue.enqueue('node1')
|
queue.enqueue('node1')
|
||||||
expect(queue.first!.value).toBe('node1')
|
expect(queue.first!.value).toBe('node1')
|
||||||
})
|
})
|
||||||
test('enque into a non-empty queue', () => {
|
test('enqueue into a non-empty queue', () => {
|
||||||
const queue = new Queue()
|
const queue = new Queue()
|
||||||
queue.enqueue('node1')
|
queue.enqueue('node1')
|
||||||
queue.enqueue('node3')
|
queue.enqueue('node3')
|
||||||
@@ -255,3 +255,11 @@ describe('enque a message into MessageQueue', () => {
|
|||||||
expect(item3).toBe(null)
|
expect(item3).toBe(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('binary search', () => {
|
||||||
|
expect(binarySearch(['a', 'b', 'd', 'e'], 'e', (a, b) => (a < b ? -1 : a === b ? 0 : 1))).toEqual([3, true])
|
||||||
|
expect(binarySearch(['a', 'b', 'd', 'e'], 'x', (a, b) => (a < b ? -1 : a === b ? 0 : 1))).toEqual([4, false])
|
||||||
|
expect(binarySearch(['a', 'b', 'd', 'e'], 'c', (a, b) => (a < b ? -1 : a === b ? 0 : 1))).toEqual([2, false])
|
||||||
|
expect(binarySearch(['a', 'b', 'd', 'e'], 'a', (a, b) => (a < b ? -1 : a === b ? 0 : 1))).toEqual([0, true])
|
||||||
|
expect(binarySearch(['a', 'b', 'd', 'e'], '[', (a, b) => (a < b ? -1 : a === b ? 0 : 1))).toEqual([0, false])
|
||||||
|
})
|
||||||
|
|||||||
99
utils.ts
99
utils.ts
@@ -13,83 +13,50 @@ export function normalizeURL(url: string): string {
|
|||||||
return p.toString()
|
return p.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array
|
|
||||||
//
|
|
||||||
export function insertEventIntoDescendingList(sortedArray: Event[], event: Event) {
|
export function insertEventIntoDescendingList(sortedArray: Event[], event: Event) {
|
||||||
let start = 0
|
const [idx, found] = binarySearch(sortedArray, event, (a, b) => {
|
||||||
let end = sortedArray.length - 1
|
if (a.id === b.id) return 0
|
||||||
let midPoint
|
if (a.created_at === b.created_at) return -1
|
||||||
let position = start
|
return b.created_at - a.created_at
|
||||||
|
})
|
||||||
if (end < 0) {
|
if (!found) {
|
||||||
position = 0
|
sortedArray.splice(idx, 0, event)
|
||||||
} else if (event.created_at < sortedArray[end].created_at) {
|
|
||||||
position = end + 1
|
|
||||||
} else if (event.created_at >= sortedArray[start].created_at) {
|
|
||||||
position = start
|
|
||||||
} else
|
|
||||||
while (true) {
|
|
||||||
if (end <= start + 1) {
|
|
||||||
position = end
|
|
||||||
break
|
|
||||||
}
|
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
|
||||||
if (sortedArray[midPoint].created_at > event.created_at) {
|
|
||||||
start = midPoint
|
|
||||||
} else if (sortedArray[midPoint].created_at < event.created_at) {
|
|
||||||
end = midPoint
|
|
||||||
} else {
|
|
||||||
// aMidPoint === num
|
|
||||||
position = midPoint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedArray
|
return sortedArray
|
||||||
}
|
}
|
||||||
|
|
||||||
export function insertEventIntoAscendingList(sortedArray: Event[], event: Event) {
|
export function insertEventIntoAscendingList(sortedArray: Event[], event: Event) {
|
||||||
let start = 0
|
const [idx, found] = binarySearch(sortedArray, event, (a, b) => {
|
||||||
let end = sortedArray.length - 1
|
if (a.id === b.id) return 0
|
||||||
let midPoint
|
if (a.created_at === b.created_at) return -1
|
||||||
let position = start
|
return a.created_at - b.created_at
|
||||||
|
})
|
||||||
|
if (!found) {
|
||||||
|
sortedArray.splice(idx, 0, event)
|
||||||
|
}
|
||||||
|
return sortedArray
|
||||||
|
}
|
||||||
|
|
||||||
if (end < 0) {
|
export function binarySearch<T>(arr: T[], val: T, compare: (a: T, b: T) => number): [number, boolean] {
|
||||||
position = 0
|
let start = 0
|
||||||
} else if (event.created_at > sortedArray[end].created_at) {
|
let end = arr.length - 1
|
||||||
position = end + 1
|
|
||||||
} else if (event.created_at <= sortedArray[start].created_at) {
|
while (start <= end) {
|
||||||
position = start
|
const mid = Math.floor((start + end) / 2)
|
||||||
} else
|
const cmp = compare(val, arr[mid])
|
||||||
while (true) {
|
|
||||||
if (end <= start + 1) {
|
if (cmp === 0) {
|
||||||
position = end
|
return [mid, true]
|
||||||
break
|
|
||||||
}
|
|
||||||
midPoint = Math.floor(start + (end - start) / 2)
|
|
||||||
if (sortedArray[midPoint].created_at < event.created_at) {
|
|
||||||
start = midPoint
|
|
||||||
} else if (sortedArray[midPoint].created_at > event.created_at) {
|
|
||||||
end = midPoint
|
|
||||||
} else {
|
|
||||||
// aMidPoint === num
|
|
||||||
position = midPoint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert when num is NOT already in (no duplicates)
|
if (cmp < 0) {
|
||||||
if (sortedArray[position]?.id !== event.id) {
|
end = mid - 1
|
||||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]
|
} else {
|
||||||
|
start = mid + 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedArray
|
return [start, false]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueueNode<V> {
|
export class QueueNode<V> {
|
||||||
|
|||||||
Reference in New Issue
Block a user