Source: utils/binary.js

/*!
 * binary.js - binary search utils for hsd
 * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
 * https://github.com/handshake-org/hsd
 */

'use strict';

/**
 * Perform a binary search on a sorted array.
 * @param {Array} items
 * @param {Object} key
 * @param {Function} compare
 * @param {Boolean} [insert=false]
 * @returns {Number} Index.
 */

exports.search = function search(items, key, compare, insert) {
  let start = 0;
  let end = items.length - 1;

  while (start <= end) {
    const pos = (start + end) >>> 1;
    const cmp = compare(items[pos], key);

    if (cmp === 0)
      return pos;

    if (cmp < 0)
      start = pos + 1;
    else
      end = pos - 1;
  }

  if (!insert)
    return -1;

  return start;
};

/**
 * Perform a binary insert on a sorted array.
 * @param {Array} items
 * @param {Object} item
 * @param {Function} compare
 * @param {Boolean} [uniq=false]
 * @returns {Number} index
 */

exports.insert = function insert(items, item, compare, uniq) {
  const i = exports.search(items, item, compare, true);

  if (uniq && i < items.length) {
    if (compare(items[i], item) === 0)
      return -1;
  }

  if (i === 0)
    items.unshift(item);
  else if (i === items.length)
    items.push(item);
  else
    items.splice(i, 0, item);

  return i;
};

/**
 * Perform a binary removal on a sorted array.
 * @param {Array} items
 * @param {Object} item
 * @param {Function} compare
 * @returns {Boolean}
 */

exports.remove = function remove(items, item, compare) {
  const i = exports.search(items, item, compare, false);

  if (i === -1)
    return false;

  splice(items, i);

  return true;
};

/*
 * Helpers
 */

/**
 * @param {Array} list
 * @param {Number} i
 */

function splice(list, i) {
  if (i === 0) {
    list.shift();
    return;
  }

  let k = i + 1;

  while (k < list.length)
    list[i++] = list[k++];

  list.pop();
}