UNPKG

sangja

Version:

JavaScript data structures library

2,336 lines 59.9 kB
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define("sangja", [], factory);
	else if(typeof exports === 'object')
		exports["sangja"] = factory();
	else
		root["sangja"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 3);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {

/**
 * Check if given object is iterable
 * @function
 * @memberof sangja
 * @param {*} obj - An object to check if iterable
 * @return {boolean} True if obj is iterable else false
 */
function isIterable(obj) {
  // checks for null and undefined
  if (obj == null) {
    return false;
  }
  return typeof obj[Symbol.iterator] === 'function';
}

/**
 * Default key function.<br>
 * Data structures that require compare will use this function as a default key function.<br>
 * Returns the input argument as it is.
 * @function
 * @memberof sangja
 */
const defaultKey = x => x;

/**
 * Default compare function.<br>
 * Data structures that require compare will use this function as a default compare function.<br>
 * Compare 2 given operands and return the result. This function can compare number, string.
 * @function
 * @memberof sangja
 */
const defaultCompare = (x, y) => {
  if (x < y) {
    return -1;
  }
  if (x > y) {
    return 1;
  }
  return 0;
};

function mergeOptions(given = {}, original = {}) {
  if (!given) {
    return original;
  }

  const merged = {};
  Object.keys(original).forEach((key) => {
    merged[key] = given[key] || original[key];
  });
  return merged;
}

module.exports = {
  isIterable,
  defaultKey,
  defaultCompare,
  mergeOptions,
};


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);
const LinkedList = __webpack_require__(2);

/**
 * @class
 * @memberof sangja
 */
class Queue {
  /**
   * Creates a new Queue.
   * Iterable parameter is optional.
   * @constructor
   * @param {iterable} [iterable] - Iterator for initialize the queue.
   * @throws {TypeError} When given parameter is not queue.
   */
  constructor(iterable = []) {
    if (!Utils.isIterable(iterable)) {
      throw TypeError();
    }
    this._linkedList = new LinkedList(iterable);
  }

  /**
   * Add value at the rear of the queue.
   * @param {*} value - The value to enqueue to the queue.
   */
  enqueue(value) {
    this._linkedList.addLast(value);
  }

  /**
   * Add values in the given iterator at the rear of the queue.
   * @param {iterable} iterable - The iterable values to enqueue
   */
  enqueueAll(iterable) {
    [...iterable].forEach(v => this._linkedList.addLast(v));
  }

  /**
   * Removes the front of the queue and returns the value at the front of the queue.
   * @returns {*} The value at the front of the queue. If empty, return undefined.
   */
  dequeue() {
    if (this._linkedList.size() === 0) {
      return undefined;
    }

    return this._linkedList.popFirst();
  }

  /**
   * Returns the value at the front of the queue without changing the state of the queue.
   * @returns {*} The value at the front of the queue. If empty, return undefined.
   */
  peek() {
    if (this._linkedList.size() === 0) {
      return undefined;
    }

    return this._linkedList.getFirst();
  }

  /**
   * Returns the number of elements in the queue.
   * @returns {number} The number of elements in the queue.
   */
  size() {
    return this._linkedList.size();
  }

  /**
   * Returns whether the queue is empty.
   * @returns {boolean} True if the queue is empty.
   */
  isEmpty() {
    return this._linkedList.isEmpty();
  }

  /**
   * Removes all values in the queue.
   */
  clear() {
    this._linkedList = new LinkedList();
  }

  /**
   * For each values in the queue, execute the given procedure f.
   * @param {function} f - Procedure to execute
   */
  forEach(f) {
    this._linkedList.forEach(f);
  }

  /**
   * Returns a new Queue whose values are mapped with given function f.
   * @param {function} f - Function to map values
   * @return {Stack} Queue([mapped values])
   */
  map(f) {
    const queue = new Queue();
    queue._linkedList = this._linkedList.map(f);
    return queue;
  }

  /**
   * Returns a new Queue whose values are mapped with given function f and flattened.
   * @param {function} f - Function (this.value) => iterable
   * @return {Stack} Queue([mapped and flattened values])
   */
  flatMap(f) {
    const queue = new Queue();
    queue._linkedList = this._linkedList.flatMap(f);
    return queue;
  }

  /**
   * Returns a new Queue whose values are filtered with given predicate f.
   * @param {function} f - Predicate (this.value) => boolean
   * @return {Stack} Queue([filtered values])
   */
  filter(f) {
    const queue = new Queue();
    queue._linkedList = this._linkedList.filter(f);
    return queue;
  }

  /**
   * Returns a new Queue whose values are reversed in order.
   * @return {Stack} Queue([reversed values])
   */
  reversed() {
    const queue = new Queue();
    queue._linkedList = this._linkedList.reversed();
    return queue;
  }

  /**
   * If any of containing values satisfies given f, return true.
   * If none of values satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  some(f) {
    return this._linkedList.some(f);
  }

  /**
   * If all of containing values satisfies given f or not contain any value, return true.
   * If any of value doesn't satisfy f, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  every(f) {
    return this._linkedList.every(f);
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @returns {boolean}
   */
  includes(v) {
    return this._linkedList.includes(v);
  }

  * [Symbol.iterator]() {
    yield* this._linkedList;
  }
}

module.exports = Queue;


/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);

/**
 * @class
 * @memberof sangja
 */
class LinkedList {
  /**
   * Creates a new LinkedList.
   * Iterable parameter is optional.
   * @constructor
   * @param {iterable} [iterable] - Iterator for initialize the list.
   * @throws {TypeError} When given parameter is not iterable.
   */
  constructor(iterable = []) {
    this._linkedList = {
      size: 0,
      front: null,
      end: null,
    };
    if (!Utils.isIterable(iterable)) {
      throw TypeError();
    }
    [...iterable].forEach(v => this.addLast(v));
  }

  /**
   * Return the node at the given index of the linked list.
   * @param {number} index - The index to get node.
   * @private
   * @return {node} The node at the given index.
   * When the given index < 0 or index >= size of the linked list, return undefined.
   */
  _getNode(index) {
    if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
      return undefined;
    }
    if (index < this._linkedList.size / 2) {
      let now = this._linkedList.front;
      for (let i = 0; i < index; i += 1) {
        now = now.next;
      }
      return now;
    }
    let now = this._linkedList.end;
    for (let i = this._linkedList.size - 1; i > index; i -= 1) {
      now = now.prev;
    }
    return now;
  }

  /**
   * Add value at the given index of the linked list.
   * @param {number} [index] - The index to add the value.
   * @param {*} value - The value to add.
   * @throws {RangeError} When the given index < 0 or index > size of the linked list.
   */
  add(index, value) {
    // Index not given. index is the value to add.
    if (value === undefined) {
      this.addLast(index);
      return;
    }
    if (typeof index !== 'number' || index < 0 || index > this._linkedList.size) {
      throw RangeError();
    }

    if (index === 0) {
      const item = {
        prev: null,
        next: this._linkedList.front,
        value,
      };
      if (this._linkedList.front) {
        this._linkedList.front.prev = item;
      } else {
        // No elements until now.
        this._linkedList.end = item;
      }
      this._linkedList.front = item;
    } else if (index === this._linkedList.size) {
      const item = {
        prev: this._linkedList.end,
        next: null,
        value,
      };
      if (this._linkedList.end) {
        this._linkedList.end.next = item;
      }
      this._linkedList.end = item;
    } else {
      const original = this._getNode(index);

      const item = {
        prev: original.prev,
        next: original,
        value,
      };
      item.prev.next = item;
      item.next.prev = item;
    }
    this._linkedList.size += 1;
  }

  /**
   * Add values in given iterator at the given index of the linked list.
   * @param {number} [index] - The index to add the value.
   * @param {iterable} iterable - The iterable object that contain values to add.
   * @throws {RangeError} When the given index < 0 or index > size of the linked list.
   */
  addAll(index, iterable) {
    // Index not given. index is iterable object.
    if (iterable === undefined) {
      this.addAllLast(index);
      return;
    }
    const values = [...iterable];
    for (let i = values.length - 1; i >= 0; i -= 1) {
      this.add(index, values[i]);
    }
  }

  /**
   * Add value at the front of the linked list.
   * @param {*} value - The value to add.
   */
  addFirst(value) {
    this.add(0, value);
  }

  /**
   * Add values in given iterator at the front of the linked list.
   * @param {iterable} iterable - The iterable object that contain values to add.
   */
  addAllFirst(iterable) {
    const values = [...iterable];
    for (let i = values.length - 1; i >= 0; i -= 1) {
      this.add(0, values[i]);
    }
  }

  /**
   * Add value at the end of the linked list.
   * @param {*} value - The value to add.
   */
  addLast(value) {
    this.add(this.size(), value);
  }

  /**
   * Add values in given iterator at the end of the linked list.
   * @param {iterable} iterable - The iterable object that contain values to add.
   */
  addAllLast(iterable) {
    const values = [...iterable];
    for (let i = 0; i < values.length; i += 1) {
      this.addLast(values[i]);
    }
  }

  /**
   * Removes the given index of the linked list and
   * returns the value at the given index of the linked list.
   * @param {number} [index] - The index to remove the value.
   * @return {*} The value at the given index of the linked list. If not found, return undefined.
   */
  pop(index) {
    if (index === undefined) {
      return this.popLast();
    }
    if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
      return undefined;
    }
    const now = this._getNode(index);

    if (now.prev) {
      now.prev.next = now.next;
    } else {
      this._linkedList.front = now.next;
    }

    if (now.next) {
      now.next.prev = now.prev;
    } else {
      this._linkedList.end = now.prev;
    }

    this._linkedList.size -= 1;
    return now.value;
  }

  /**
   * Removes the first of the linked list and
   * returns the value at the first of the linked list.
   * @return {*} The value at the front of the linked list. If empty, return undefined.
   */
  popFirst() {
    return this.pop(0);
  }

  /**
   * Removes the end of the linked list and
   * returns the value at the end of the linked list.
   * @return {*} The value at the end of the linked list. If empty, return undefined.
   */
  popLast() {
    return this.pop(this.size() - 1);
  }

  /**
   * Same with pop(i) except that index is required.
   * @param {number} index - The index to remove the value.
   * @return {(*|undefined)} The value at the given index of the linked list.
   * If not found, return undefined.
   */
  removeAt(index) {
    if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
      return undefined;
    }
    return this.pop(index);
  }

  /**
   * Removes the first occurance of the given value in the linked list and
   * returns true if the given value is in the linked list.
   * @param {*} value - The value to remove
   * @return {boolean} True if the given value is in the linked list else false.
   */
  remove(value) {
    let now = this._linkedList.front;
    while (now) {
      if (now.value === value) {
        break;
      }
      now = now.next;
    }

    if (!now) {
      return false;
    }

    if (now.prev) {
      now.prev.next = now.next;
    } else {
      // now is front
      this._linkedList.front = now.next;
    }

    if (now.next) {
      now.next.prev = now.prev;
    } else {
      // now is end
      this._linkedList.end = now.prev;
    }

    this._linkedList.size -= 1;
    return true;
  }

  /**
   * Removes the every occurance of the given value in the linked list and
   * returns the number of removed values.
   * @param {*} value - The value to remove
   * @return {number} The number of removed values.
   */
  removeAll(value) {
    let now = this._linkedList.front;
    let result = 0;
    while (now) {
      if (now.value === value) {
        if (now.prev) {
          now.prev.next = now.next;
        } else {
          // now is front
          this._linkedList.front = now.next;
        }

        if (now.next) {
          now.next.prev = now.prev;
        } else {
          // now is end
          this._linkedList.end = now.prev;
        }

        this._linkedList.size -= 1;
        result += 1;
      }
      now = now.next;
    }

    return result;
  }

  /**
   * Same with remove(value) if value is given.
   * If value is not given, same with popFirst().
   * @param {*} [value] - The value to remove
   * @return {(*|undefined|boolean)} If remove success, return true.
   * If value not given, return popFirst().
   */
  removeFirst(value) {
    if (value === undefined) {
      return this.popFirst();
    }
    return this.remove(value);
  }

  /**
   * Same with remove(value) but find from start searching from last.
   * @param {*} [value] - The value to remove
   * @return {(*|undefined|boolean)} If remove success, return true.
   * If value not given, return popLast().
   */
  removeLast(value) {
    let now = this._linkedList.end;
    while (now) {
      if (now.value === value) {
        break;
      }
      now = now.prev;
    }

    if (!now) {
      return false;
    }

    if (now.prev) {
      now.prev.next = now.next;
    } else {
      // now is front
      this._linkedList.front = now.next;
    }

    if (now.next) {
      now.next.prev = now.prev;
    } else {
      // now is end
      this._linkedList.end = now.prev;
    }

    this._linkedList.size -= 1;
    return true;
  }

  /**
   * Removes the first value that matches given predicate f and
   * returns value in the linked list.
   * @param {Function} f - Predicate
   * @return {(*|undefined)} Found value. If not found, return undefined.
   * @throws {TypeError} When the given predicate is not a function.
   */
  removeMatch(f) {
    if (typeof f !== 'function') {
      throw TypeError();
    }

    let now = this._linkedList.front;
    while (now) {
      if (f(now.value)) {
        break;
      }
      now = now.next;
    }

    if (!now) {
      return undefined;
    }

    if (now.prev) {
      now.prev.next = now.next;
    } else {
      // now is front
      this._linkedList.front = now.next;
    }

    if (now.next) {
      now.next.prev = now.prev;
    } else {
      // now is end
      this._linkedList.end = now.prev;
    }

    this._linkedList.size -= 1;
    return now.value;
  }

  /**
   * Removes all values that matches given predicate f and
   * returns the removed values.
   * @param {Function} f - Predicate
   * @return {any[]} Removed values.
   * @throws {TypeError} When the given predicate is not a function.
   */
  removeMatchAll(f) {
    if (typeof f !== 'function') {
      throw TypeError();
    }

    let now = this._linkedList.front;
    const result = [];
    while (now) {
      if (f(now.value)) {
        if (now.prev) {
          now.prev.next = now.next;
        } else {
          // now is front
          this._linkedList.front = now.next;
        }

        if (now.next) {
          now.next.prev = now.prev;
        } else {
          // now is end
          this._linkedList.end = now.prev;
        }

        this._linkedList.size -= 1;
        result.push(now.value);
      }
      now = now.next;
    }

    return result;
  }

  /**
   * Same with removeMatch(f)
   * @param {Function} f - Predicate
   * @return {(*|undefined)} Found value. If not found, return undefined.
   * @throws {TypeError} When the given predicate is not a function.
   */
  removeMatchFirst(f) {
    return this.removeMatch(f);
  }

  /**
   * Same with removeMatch(f) but find from start searching from last.
   * @param {Function} f - Predicate
   * @return {(*|undefined)} Found value. If not found, return undefined.
   * @throws {TypeError} When the given predicate is not a function.
   */
  removeMatchLast(f) {
    if (typeof f !== 'function') {
      throw TypeError();
    }

    let now = this._linkedList.end;
    while (now) {
      if (f(now.value)) {
        break;
      }
      now = now.prev;
    }

    if (!now) {
      return undefined;
    }

    if (now.prev) {
      now.prev.next = now.next;
    } else {
      // now is front
      this._linkedList.front = now.next;
    }

    if (now.next) {
      now.next.prev = now.prev;
    } else {
      // now is end
      this._linkedList.end = now.prev;
    }

    this._linkedList.size -= 1;
    return now.value;
  }

  /**
   * Removes all values in the linked list.
   */
  clear() {
    this._linkedList = {
      size: 0,
      front: null,
      end: null,
    };
  }

  /**
   * Returns the value at the given index of the linked list.
   * @param {number} index - The index to get the value.
   * @return {*} The value at the given index of the linked list.
   * When the given index < 0 or index >= size of the linked list, return undefined.
   */
  get(index) {
    if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
      return undefined;
    }
    const now = this._getNode(index);

    return now.value;
  }

  /**
   * Returns the value at the first of the linked list.
   * @return {*} The value at the front of the linked list. If empty, return undefined.
   */
  getFirst() {
    return this.get(0);
  }

  /**
   * Returns the value at the end of the linked list.
   * @return {*} The value at the end of the linked list. If empty, return undefined.
   */
  getLast() {
    return this.get(this.size() - 1);
  }

  /**
   * Updates the value at the given index of the linked list and
   * returns the value at the given index of the linked list.
   * @param {number} index - The index to update the value.
   * @param {*} value - The value to update.
   * @throws {RangeError} When the given index < 0 or index >= size of the linked list.
   * @return {*} The value at the given index of the linked list.
   */
  set(index, value) {
    if (typeof index !== 'number' || index < 0 || index >= this._linkedList.size) {
      throw RangeError();
    }
    const now = this._getNode(index);

    const ret = now.value;
    now.value = value;

    return ret;
  }

  /**
   * Returns the value of the first element in the linked list
   * that satisfies the provided testing function.
   * @param {function} f - Testing function.
   * @return {*} The the first value in the linked list
   * that satisfies the provided testing function.
   * When no element in the linked list satisfies the provided testing function, return undefined.
   */
  find(f) {
    let now = this._linkedList.front;
    while (now && !f(now.value)) {
      now = now.next;
    }
    if (now) {
      return now.value;
    }
    return undefined;
  }

  /**
   * Returns the number of elements in the linked list.
   * @return {number} The number of elements in the linked list.
   */
  size() {
    return this._linkedList.size;
  }

  /**
   * Returns whether the linked list is empty.
   * @return {boolean} True if the linked list is empty.
   */
  isEmpty() {
    return this._linkedList.size === 0;
  }

  /**
   * For each values in the list, execute the given procedure f.
   * @param {function} f - Procedure to execute
   */
  forEach(f) {
    let now = this._linkedList.front;
    while (now) {
      f(now.value);
      now = now.next;
    }
  }

  /**
   * Returns a new LinkedList whose values are mapped with given function f.
   * @param {function} f - Function to map values
   * @return {LinkedList} LinkedList([mapped values])
   */
  map(f) {
    const list = new LinkedList();
    this.forEach(v => list.addLast(f(v)));
    return list;
  }

  /**
   * Returns a new LinkedList whose values are mapped with given function f and flattened.
   * @param {function} f - Function (this.value) => iterable
   * @return {LinkedList} LinkedList([mapped and flattened values])
   */
  flatMap(f) {
    const list = new LinkedList();
    this.forEach(v => list.addAllLast([...f(v)]));
    return list;
  }

  /**
   * Returns a new LinkedList whose values are filtered with given predicate f.
   * @param {function} f - Predicate (this.value) => boolean
   * @return {LinkedList} LinkedList([filtered values])
   */
  filter(f) {
    const list = new LinkedList();
    this.forEach((v) => {
      if (f(v)) {
        list.addLast(v);
      }
    });
    return list;
  }

  /**
   * Returns a new LinkedList whose values are reversed in order.
   * @return {LinkedList} LinkedList([reversed values])
   */
  reversed() {
    const list = new LinkedList();
    this.forEach(v => list.addFirst(v));
    return list;
  }

  /**
   * If any of containing values satisfies given f, return true.
   * If none of values satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @return {boolean}
   */
  some(f) {
    if (this.size() === 0) {
      return false;
    }

    let now = this._linkedList.front;
    while (now) {
      if (f(now.value)) {
        return true;
      }
      now = now.next;
    }
    return false;
  }

  /**
   * If all of containing values satisfies given f or not contain any value, return true.
   * If any of value doesn't satisfy f, return false.
   * @param {function} f - Predicate
   * @return {boolean}
   */
  every(f) {
    let now = this._linkedList.front;
    while (now) {
      if (!f(now.value)) {
        return false;
      }
      now = now.next;
    }
    return true;
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @return {boolean}
   */
  includes(v) {
    let now = this._linkedList.front;
    while (now) {
      if (now.value === v) {
        return true;
      }
      now = now.next;
    }
    return false;
  }

  * [Symbol.iterator]() {
    let now = this._linkedList.front;
    while (now) {
      yield now.value;
      now = now.next;
    }
  }
}

module.exports = LinkedList;


/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);
const Optional = __webpack_require__(4);
const Stack = __webpack_require__(5);
const Queue = __webpack_require__(1);
const LinkedList = __webpack_require__(2);
const Heap = __webpack_require__(6);
const BinarySearchTree = __webpack_require__(7);

/**
 * @namespace sangja
 */
module.exports = {
  Optional,
  Stack,
  Queue,
  LinkedList,
  Heap,
  BinarySearchTree,
  isIterable: Utils.isIterable,
  defaultKey: Utils.defaultKey,
  defaultCompare: Utils.defaultCompare,
};


/***/ }),
/* 4 */
/***/ (function(module, exports) {

/**
 * @class
 * @memberof sangja
 */
class Optional {
  /**
   * Creates a new Optional.
   * Value parameter is optional. Undefeined for value is not allowed.(Not work well)
   * @constructor
   * @param {*} [value=undefined] - Value to contain
   */
  constructor(value = undefined) {
    this.value = value;
  }

  /**
   * Returns the containing value.
   * @returns {*|undefined} The containing value. If it does not contain a value, return undefined
   */
  get() {
    return this.value;
  }

  /**
   * Returns the containing value.
   * @returns {*} The containing value. If it does not contain a value, return undefined
   */
  getOrElse(value) {
    if (this.value === undefined) {
      return value;
    }
    return this.value;
  }

  /**
   * If the optional contains a value, returns 1 else 0.
   * @returns {number} The number of elements in the optional(0 or 1)
   */
  size() {
    if (this.value === undefined) {
      return 0;
    }
    return 1;
  }

  /**
   * If the optional is empty, returns true else returns false.
   * @returns {boolean} True if the optional is empty else false
   */
  isEmpty() {
    if (this.value === undefined) {
      return true;
    }
    return false;
  }

  /**
   * If the optional contains a value, execute the given function f.
   * @param {function} f - Function to execute
   */
  forEach(f) {
    if (this.value === undefined) {
      return;
    }
    f(this.value);
  }

  /**
   * If the optional contains a value, execute the given function f
   * and returns the new optional containing f(this.value).<br>
   * If the optional is empty or catch error while executing f, returns empty optional.
   * @param {function} f - Function to execute with this.value
   * @return {Optional} Optional(f(this.value)) or Optional()
   */
  map(f) {
    if (this.value === undefined) {
      return new Optional();
    }

    try {
      return new Optional(f(this.value));
    } catch (err) {
      return new Optional();
    }
  }

  /**
   * If the optional contains a value, execute the given function f
   * and flatten the result.<br>
   * Returns the new optional containing flatten result of f(this.value)<br>
   * If the optional is empty or catch error while executing f, returns empty optional.
   * @param {function} f - (this.value) => Optional
   * @return {Optional} Optional(...f(this.value)) or Optional()
   */
  flatMap(f) {
    if (this.value === undefined) {
      return new Optional();
    }

    try {
      return new Optional(...f(this.value));
    } catch (err) {
      return new Optional();
    }
  }

  /**
   * If the contained value satisfies the predicate, return this.
   * If the optional is empty or given predicate returns false, returns empty optional.
   * @param {function} f - Predicate
   * @return {Optional} Optional(this.value) or Optional()
   */
  filter(f) {
    if (this.value === undefined) {
      return new Optional();
    }

    if (f(this.value)) {
      return this;
    }
    return new Optional();
  }

  /**
   * If containing value satisfies given f, return true.
   * If not satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  some(f) {
    if (this.value === undefined) {
      return false;
    }
    return Boolean(f(this.value));
  }

  /**
   * If not contain any value or containing value satisfies given f, return true.
   * If not satisfy f, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  every(f) {
    if (this.value === undefined) {
      return true;
    }
    return Boolean(f(this.value));
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @returns {boolean}
   */
  includes(v) {
    if (this.value !== undefined && this.value === v) {
      return true;
    }
    return false;
  }

  * [Symbol.iterator]() {
    if (this.value !== undefined) {
      yield this.value;
    }
  }
}

module.exports = Optional;


/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);

/**
 * @class
 * @memberof sangja
 */
class Stack {
  /**
   * Creates a new Stack.
   * Iterable parameter is optional.
   * @constructor
   * @param {iterable} [iterable] - Iterator for initialize the stack.
   * @throws {TypeError} When given parameter is not stack.
   */
  constructor(iterable = []) {
    if (!Utils.isIterable(iterable)) {
      throw TypeError();
    }
    this._stack = [...iterable];
  }

  /**
   * Add value at the top of the stack.
   * @param {*} value - The value to push to the stack.
   */
  push(value) {
    this._stack.push(value);
  }

  /**
   * Add values in the given iterator at the top of the stack.
   * @param {iterable} iterable - The iterable values to push to the stack.
   */
  pushAll(iterable) {
    [...iterable].forEach(v => this._stack.push(v));
  }

  /**
   * Removes the top of the stack and returns the value at the top of the stack.
   * @returns {*} The value at the top of the stack. If empty, return undefined.
   */
  pop() {
    if (this._stack.length === 0) {
      return undefined;
    }

    return this._stack.pop();
  }

  /**
   * Returns the value at the top of the stack without changing the state of the stack.
   * @returns {*} The value at the top of the stack. If empty, return undefined.
   */
  top() {
    if (this._stack.length === 0) {
      return undefined;
    }

    return this._stack[this._stack.length - 1];
  }

  /**
   * Removes all values in the stack.
   */
  clear() {
    this._stack = [];
  }

  /**
   * Returns the number of elements in the stack.
   * @returns {number} The number of elements in the stack.
   */
  size() {
    return this._stack.length;
  }

  /**
   * Returns whether the stack is empty.
   * @returns {boolean} True if the stack is empty.
   */
  isEmpty() {
    return this._stack.length === 0;
  }

  /**
   * For each values in the stack, execute the given procedure f.<br>
   * *Executing order is top to bottom*
   * @param {function} f - Procedure to execute
   */
  forEach(f) {
    for (let i = this._stack.length - 1; i >= 0; i -= 1) {
      f(this._stack[i]);
    }
  }

  /**
   * Returns a stack whose values are mapped with given function f.
   * @param {function} f - Function to map values
   * @return {Stack} Stack([mapped values])
   */
  map(f) {
    const stack = new Stack();
    stack._stack = this._stack.map(f);
    return stack;
  }

  /**
   * Returns a stack whose values are mapped with given function f and flattened.
   * @param {function} f - Function (this.value) => iterable
   * @return {Stack} Stack([mapped and flattened values])
   */
  flatMap(f) {
    const stack = new Stack();
    // [...this._stack.map(f)].forEach(arr => arr.forEach(v => stack.push(v)));
    this._stack.map(f).forEach(arr => stack.pushAll(arr));
    return stack;
  }

  /**
   * Returns a stack whose values are filtered with given predicate f.
   * @param {function} f - Predicate (this.value) => boolean
   * @return {Stack} Stack([filtered values])
   */
  filter(f) {
    const stack = new Stack();
    stack._stack = this._stack.filter(f);
    return stack;
  }

  /**
   * Returns a stack whose values are reversed in order.
   * @return {Stack} Stack([reversed values])
   */
  reversed() {
    return new Stack(this);
  }

  /**
   * If any of containing values satisfies given f, return true.
   * If none of values satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  some(f) {
    return this._stack.some(f);
  }

  /**
   * If all of containing values satisfies given f or not contain any value, return true.
   * If any of value doesn't satisfy f, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  every(f) {
    return this._stack.every(f);
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @returns {boolean}
   */
  includes(v) {
    return this._stack.includes(v);
  }

  * [Symbol.iterator]() {
    for (let i = this._stack.length - 1; i >= 0; i -= 1) {
      yield this._stack[i];
    }
  }
}

module.exports = Stack;


/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);

/**
 * @class
 * @memberof sangja
 */
class Heap {
  /**
   * Creates a new Heap.
   * By default, max-heap is created.
   * Iterable a and option object b are optional. But if both are given, a must precede b.
   * @constructor
   * @param {iterable} [a=[]] - Iterator for initialize
   * @param {Object} [b={}] - Option object for initialize
   * @param {function} [b.key=sangja.defaultKey] - Key function for each value.
   * Each value should be comparable with given key.
   * @param {function} [b.compare=sangja.defaultCompare] - Compare function.<br>
   * If x precede y, compare(key(x), key(y)) < 0<br>
   * If y precede x, compare(key(x), key(y)) > 0<br>
   * If the order of x and y is the same, compare(key(x), key(y)) == 0
   * @param {function} [b.reverse=false] - If true, compare result is inverted.
   */
  constructor(a = {}, b = {}) {
    // null, null -> iterator: [], key,compare: default
    // iterator, null -> iterator: ok, key,compare: default
    // option, null -> iterator: [], key,compare: option
    // iterator, option -> iterator: ok, key,compare: option
    let iterator = null;
    let key = null;
    let compare = null;
    let reverse = null;
    if (Utils.isIterable(a)) {
      iterator = a;
      // If a is an iterable, b will be an option object.(If not given, {})
      ({ key, compare, reverse } = b);
    } else {
      iterator = [];
      // If a is not an iterable, a will be an option object.(If not given, {})
      ({ key, compare, reverse } = a);
    }

    this._heap = [0];
    this._options = {
      key: key || Utils.defaultKey,
      compare: compare || Utils.defaultCompare,
      reverse: reverse || false,
    };

    this._key = this._options.key;
    if (this._options.reverse) {
      this._compare = (x, y) => this._options.compare(this._key(y), this._key(x));
    } else {
      this._compare = (x, y) => this._options.compare(this._key(x), this._key(y));
    }

    [...iterator].forEach(v => this.add(v));
  }

  /**
   * Add value to the the heap.
   * @param {*} value - The value to add
   */
  add(value) {
    this._heap.push(value);

    let now = this._heap.length - 1;
    let next = Math.floor(now / 2);
    while (now > 1 && this._compare(this._heap[next], this._heap[now]) < 0) {
      const tmp = this._heap[next];
      this._heap[next] = this._heap[now];
      this._heap[now] = tmp;

      now = next;
      next = Math.floor(now / 2);
    }
  }

  /**
   * Add values to the the heap.
   * @param {iterable} iterable - The iterable object that contain values to add.
   */
  addAll(iterable) {
    [...iterable].forEach(v => this.add(v));
  }

  /**
   * Removes the root of the heap and returns the value.
   * @returns {*} The value at the root of the heap. If empty, return undefined.
   */
  pop() {
    if (this._heap.length === 1) {
      return undefined;
    }
    if (this._heap.length === 2) {
      return this._heap.pop();
    }

    const value = this._heap[1];
    this._heap[1] = this._heap.pop();

    let now = 1;
    while (now < this._heap.length) {
      const left = now * 2;
      const right = now * 2 + 1;
      // If now < right child, now <- max(left, right) and continue
      if (right < this._heap.length
          && this._compare(this._heap[now], this._heap[right]) < 0) {
        let next = null;
        if (this._compare(this._heap[left], this._heap[right]) < 0) {
          next = right;
        } else {
          next = left;
        }
        const tmp = this._heap[now];
        this._heap[now] = this._heap[next];
        this._heap[next] = tmp;
        now = next;
      } else if (left < this._heap.length
          && this._compare(this._heap[now], this._heap[left]) < 0) {
        const tmp = this._heap[now];
        this._heap[now] = this._heap[left];
        this._heap[left] = tmp;
        now = left;
      } else {
        break;
      }
    }
    return value;
  }

  /**
   * Returns the value at the root of the heap without changing the state of the heap.
   * @returns {*} The value at the root of the heap. If empty, return undefined.
   */
  peek() {
    if (this._heap.length === 1) {
      return undefined;
    }

    return this._heap[1];
  }

  /**
   * Returns the value of the first element in the heap
   * that satisfies the given predicate.<br>
   * Searches matching value by bfs order.
   * @param {function} f - Predicate
   * @returns {(*|undefined)} The the first value in the heap
   * that satisfies the provided testing function.
   * When no element in the heap satisfies the provided testing function, return undefined.
   */
  find(f) {
    for (let i = 1; i < this._heap.length; i += 1) {
      if (f(this._heap[i])) {
        return this._heap[i];
      }
    }
    return undefined;
  }

  /**
   * Returns the number of elements in the heap.
   * @returns {number} The number of elements in the heap.
   */
  size() {
    return this._heap.length - 1;
  }

  /**
   * Returns whether the heap is empty.
   * @returns {boolean} True if the heap is empty.
   */
  isEmpty() {
    return this._heap.length === 1;
  }

  /**
   * Removed all elements in the heap.
   */
  clear() {
    this._heap = [0];
  }

  /**
   * Execute the given procedure f for each values.
   * @param {function} f - Procedure to execute
   */
  forEach(f) {
    const heapForIter = new Heap(this._heap.slice(1), this._options);
    while (!heapForIter.isEmpty()) {
      f(heapForIter.pop());
    }
  }

  /**
   * Returns a new Heap mapped with given function f.
   * @param {function} f - Function
   * @param {Object} [options=this._options] - Option object for initialize the heap.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {Heap} Heap([mapped values])
   */
  map(f, options) {
    const heap = new Heap(Utils.mergeOptions(options, this._options));
    this.forEach(v => heap.add(f(v)));
    return heap;
  }

  /**
   * Returns a new Heap whose values are mapped with given function f and flattened.
   * @param {function} f - Function (this.value) => iterable
   * @param {Object} [options=this._options] - Option object for initialize the heap.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {Heap} Heap([mapped and flattened values])
   */
  flatMap(f, options) {
    const heap = new Heap(Utils.mergeOptions(options, this._options));
    this.forEach(v => heap.addAll([...f(v)]));
    return heap;
  }

  /**
   * Returns a new Heap whose values are filtered with given predicate f.
   * @param {function} f - Predicate (this.value) => boolean
   * @param {Object} [options=this._options] - Option object for initialize the heap.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {Heap} Heap([filtered values])
   */
  filter(f, options) {
    const heap = new Heap(Utils.mergeOptions(options, this._options));
    this.forEach((v) => {
      if (f(v)) {
        heap.add(v);
      }
    });
    return heap;
  }

  /**
   * Return new heap with same items, but reversed option is inverted from this.
   * @return {Heap} Heap([reversed values])
   */
  reversed() {
    return new Heap(this, Utils.mergeOptions({ reverse: !this._options.reverse }, this._options));
  }

  /**
   * If any of containing values satisfies given f, return true.
   * If none of values satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  some(f) {
    for (let i = 1; i < this._heap.length; i += 1) {
      if (f(this._heap[i])) {
        return true;
      }
    }
    return false;
  }

  /**
   * If all of containing values satisfies given f or not contain any value, return true.
   * If any of value doesn't satisfy f, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  every(f) {
    for (let i = 1; i < this._heap.length; i += 1) {
      if (!f(this._heap[i])) {
        return false;
      }
    }
    return true;
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @returns {boolean}
   */
  includes(v) {
    for (let i = 1; i < this._heap.length; i += 1) {
      if (this._heap[i] === v) {
        return true;
      }
    }
    return false;
  }

  * [Symbol.iterator]() {
    // Use other heap!
    const heapForIter = new Heap(this._heap.slice(1), this._options);

    while (!heapForIter.isEmpty()) {
      yield heapForIter.pop();
    }
  }

  /**
   * Returns breadth first iterator.
   * @param {Function} [f] - If f is given, execute f by bfs order.
   * @returns {(generator|undefined)} Tree breadth first iterator. If f if given, not return.
   */
  // eslint-disable-next-line consistent-return
  breadthFirst(f) {
    if (!f) {
      const that = this;
      return (function* _breadthFirst() {
        for (let i = 1; i < that._heap.length; i += 1) {
          yield that._heap[i];
        }
      }());
    }
    for (let i = 1; i < this._heap.length; i += 1) {
      f(this._heap[i]);
    }
  }
}

module.exports = Heap;


/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

const Utils = __webpack_require__(0);
const Queue = __webpack_require__(1);

/**
 * @class
 * @memberof sangja
 */
class BinarySearchTree {
  /**
   * Creates a new BinarySearchTree.
   * Iterable a and option object b are optional. But if both are given, a must precede b.
   * @constructor
   * @param {iterable} [a=[]] - Iterator for initialize
   * @param {Object} [b={}] - Option object
   * @param {function} [b.key=utils.defaultKey] - Key function for each value.
   * Each value should be comparable with given key.
   * @param {function} [b.compare=utils.defaultCompare] - Compare function.<br>
   * If x precede y, compare(key(x), key(y)) < 0<br>
   * If y precede x, compare(key(x), key(y)) > 0<br>
   * If the order of x and y is the same, compare(key(x), key(y)) == 0
   * @param {function} [b.reverse=false] - If true, compare result is inverted.
   */
  constructor(a = {}, b = {}) {
    // null, null -> iterator: [], key,compare: default
    // iterator, null -> iterator: ok, key,compare: default
    // option, null -> iterator: [], key,compare: option
    // iterator, option -> iterator: ok, key,compare: option
    let iterator = null;
    let key = null;
    let compare = null;
    let reverse = null;
    if (Utils.isIterable(a)) {
      iterator = a;
      // If a is an iterable, b will be an option object.(If not given, {})
      ({ key, compare, reverse } = b);
    } else {
      iterator = [];
      // If a is not an iterable, a will be an option object.(If not given, {})
      ({ key, compare, reverse } = a);
    }

    this._root = null;
    this._options = {
      key: key || Utils.defaultKey,
      compare: compare || Utils.defaultCompare,
      reverse: reverse || false,
    };

    this._key = this._options.key;
    if (this._options.reverse) {
      this._compare = (x, y) => this._options.compare(this._key(y), this._key(x));
    } else {
      this._compare = (x, y) => this._options.compare(this._key(x), this._key(y));
    }

    [...iterator].forEach(v => this.add(v));
  }

  /**
   * Add value to the tree.
   * @param {*} value - The value to add to the tree.
   */
  add(value) {
    if (this._root == null) {
      this._root = {
        left: null,
        right: null,
        children: 0,
        value,
      };
      return;
    }

    let parent = null;
    let now = this._root;
    let direction = null; // 0 if left else 1;
    while (now) {
      parent = now;
      now.children += 1;
      if (this._compare(value, now.value) <= 0) {
        now = now.left;
        direction = 0;
      } else {
        now = now.right;
        direction = 1;
      }
    }

    now = {
      left: null,
      right: null,
      children: 0,
      value,
    };
    if (direction === 0) {
      parent.left = now;
    } else {
      parent.right = now;
    }
  }

  /**
   * Add values to the the tree.
   * @param {iterable} iterable - The iterable object that contain values to add.
   */
  addAll(iterable) {
    [...iterable].forEach(v => this.add(v));
  }

  /**
   * Removes the lowest value of the tree and returns the value.
   * @returns {*} The lowest value of the tree. If empty, return undefined.
   */
  pop() {
    if (this._root === null) {
      return undefined;
    }

    let parent = null;
    let now = this._root;
    while (now.left) {
      now.children -= 1;
      parent = now;
      now = now.left;
    }

    if (parent !== null) {
      parent.left = now.right;
    } else {
      this._root = now.right;
    }

    return now.value;
  }

  /**
   * Removes the given value in the tree and returns the value.
   * @returns {(*|undefined)} The lowest value of the tree. If empty or not found, return undefined.
   */
  remove(v) {
    if (this._root === null || !this.includes(v)) {
      return undefined;
    }

    let parent = null;
    let now = this._root;
    while (now) {
      const comp = this._compare(this._key(v), this._key(now.value));
      if (comp === 0) {
        break;
      } else if (comp < 0) {
        now.children -= 1;
        parent = now;
        now = now.left;
      } else {
        now.children -= 1;
        parent = now;
        now = now.right;
      }
    }

    // Not found
    if (now === null) {
      return undefined;
    }

    // If now has both child, move left rightmost child.
    if (now.left && now.right) {
      let rightmostParent = now;
      let rightmost = now.left;
      while (rightmost.right) {
        rightmostParent.children -= 1;
        rightmostParent = rightmost;
        rightmost = rightmost.right;
      }
      if (rightmostParent !== now) {
        // Found rightmost.
        rightmostParent.right = rightmost.left;
      } else {
        // Rightmost is now.left
        rightmostParent.left = rightmost.left;
      }
      const result = now.value;
      now.value = rightmost.value;
      return result;
    }

    // If now has left child, remove now.
    if (now.left) {
      if (now === this._root) {
        this._root = now.left;
      } else if (parent.left === now) {
        parent.left = now.left;
      } else {
        parent.right = now.left;
      }
      return now.value;
    }

    // If now has right child, remove now.
    if (now.right) {
      if (now === this._root) {
        this._root = now.right;
      } else if (parent.left === now) {
        parent.left = now.right;
      } else {
        parent.right = now.right;
      }
      return now.value;
    }

    // If now is left, remove now from parent.
    if (now === this._root) {
      this._root = null;
    } else if (parent.left === now) {
      parent.left = null;
    } else {
      parent.right = null;
    }
    return now.value;
  }

  /**
   * Removes a value that matches given predicate f and
   * returns value in the linked list.
   * @param {Function} f - Predicate
   * @returns {(*|undefined)} Found value. If not found, return undefined.
   * @throws {TypeError} When the given predicate is not a function.
   */
  removeMatch(f) {
    if (typeof f !== 'function') {
      throw TypeError();
    }

    if (this.isEmpty()) {
      return undefined;
    }

    function _getMatch(node) {
      if (f(node.value)) {
        return node.value;
      }
      return (node.left && _getMatch(node.left))
        || (node.right && _getMatch(node.right));
    }
    const removeVal = _getMatch(this._root);
    this.remove(removeVal);
    return removeVal;
  }

  /**
   * Returns the lowest value of the tree without changing the state of the tree.
   * @returns {*} The lowest value of the tree. If empty, return undefined.
   */
  peek() {
    if (this._root === null) {
      return undefined;
    }

    let now = this._root;
    while (now) {
      if (now.left) {
        now = now.left;
      }
    }

    return now.value;
  }

  /**
   * Returns the value of the first element in the binary search tree
   * that satisfies the given predicate.<br>
   * Searches matching value by dfs order(preorder).
   * @param {function} f - Predicate
   * @returns {(*|undefined)} The the first value in the binary search tree
   * that satisfies the provided testing function.
   * When no element in the binary search tree satisfies
   * the provided testing function, return undefined.
   */
  find(f) {
    const nodes = [this._root];
    while (nodes.length > 0) {
      const now = nodes.pop();
      if (now) {
        if (f(now.value)) {
          return now.value;
        }
        nodes.push(now.left);
        nodes.push(now.right);
      }
    }
    return undefined;
  }

  /**
   * Returns the number of elements in the tree.
   * @returns {number} The number of elements in the tree.
   */
  size() {
    if (this._root === null) {
      return 0;
    }

    return this._root.children + 1;
  }

  /**
   * Returns whether the tree is empty.
   * @returns {boolean} True if the tree is empty.
   */
  isEmpty() {
    return this._root === null;
  }

  /**
   * Removed all elements in the tree.
   */
  clear() {
    this._root = null;
  }

  /**
   * Execute the given procedure f for each values.
   * @param {function} f - Procedure to execute
   */
  forEach(f) {
    function _forEach(node) {
      if (node) {
        f(node.value);
        _forEach(node.left);
        _forEach(node.right);
      }
    }

    _forEach(this._root);
  }

  /**
   * Returns a new BinarySearchTree mapped with given function f.
   * @param {function} f - Function
   * @param {Object} [options=this._options] - Option object for initialize.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {BinarySearchTree} BinarySearchTree([mapped values])
   */
  map(f, options) {
    const tree = new this.constructor(Utils.mergeOptions(options, this._options));
    this.forEach(v => tree.add(f(v)));
    return tree;
  }

  /**
   * Returns a new BinarySearchTree whose values are mapped with given function f and flattened.
   * @param {function} f - Function (this.value) => iterable
   * @param {Object} [options=this._options] - Option object for initialize.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {BinarySearchTree} BinarySearchTree([mapped and flattened values])
   */
  flatMap(f, options) {
    const tree = new this.constructor(Utils.mergeOptions(options, this._options));
    this.forEach(v => tree.addAll([...f(v)]));
    return tree;
  }

  /**
   * Returns a new BinarySearchTree whose values are filtered with given predicate f.
   * @param {function} f - Predicate (this.value) => boolean
   * @param {Object} [options=this._options] - Option object for initialize.<br>
   * If not given, inherits from this.
   * If only a portion is given, ingerits those that are not given.
   * @return {BinarySearchTree} BinarySearchTree([filtered values])
   */
  filter(f, options) {
    const tree = new this.constructor(Utils.mergeOptions(options, this._options));
    this.forEach((v) => {
      if (f(v)) {
        tree.add(v);
      }
    });
    return tree;
  }

  /**
   * Return new tree with same items, but reversed option is inverted from this.
   * @return {BinarySearchTree} BinarySearchTree([reversed values])
   */
  reversed() {
    return new this.constructor(this,
      Utils.mergeOptions({ reverse: !this._options.reverse }, this._options));
  }

  /**
   * If any of containing values satisfies given f, return true.
   * If none of values satisfy f or not contain any value, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  some(f) {
    function _some(node) {
      return f(node.value)
        || Boolean(node.left && _some(node.left))
        || Boolean(node.right && _some(node.right));
    }
    return Boolean(this._root) && _some(this._root);
  }

  /**
   * If all of containing values satisfies given f or not contain any value, return true.
   * If any of value doesn't satisfy f, return false.
   * @param {function} f - Predicate
   * @returns {boolean}
   */
  every(f) {
    function _every(node) {
      return f(node.value)
        && Boolean(!node.left || _every(node.left))
        && Boolean(!node.right || _every(node.right));
    }
    return !this._root || _every(this._root);
  }

  /**
   * If contains given value v, return true.
   * @param {*} v
   * @returns {boolean}
   */
  includes(v) {
    let now = this._root;
    while (now) {
      const comp = this._compare(this._key(v), this._key(now.value));
      if (comp === 0) {
        return true;
      }
      if (comp < 0) {
        now = now.left;
      } else {
        now = now.right;
      }
    }
    return false;
  }

  /**
   * Returns whether the tree is empty.
   * @name Symbol.iterator
   * @generator
   * @property {generator}
   * @returns {boolean} True if the tree is empty.
   */
  * [Symbol.iterator]() {
    yield* this.inorder();
  }

  /**
   * Returns inorder iterator.
   * @param {Function} [f] - If f is given, execute f by inorder.
   * @returns {(generator|undefined)} Tree inorder iterator. If f if given, not return.
   */
  // eslint-disable-next-line consistent-return
  inorder(f) {
    if (!f) {
      return (function* _inorderIterator(node) {
        if (node !== null) {
          yield* _inorderIterator(node.left);
          yield node.value;
          yield* _inorderIterator(node.right);
        }
      }(this._root));
    }

    function _inorder(node) {
      if (node !== null) {
        _inorder(node.left);
        f(node.value);
        _inorder(node.right);
      }
    }
    _inorder(this._root);
  }

  /**
   * Returns preorder iterator.
   * @param {Function} [f] - If f is given, execute f by preorder.
   * @returns {(generator|undefined)} Tree preorder iterator. If f if given, not return.
   */
  // eslint-disable-next-line consistent-return
  preorder(f) {
    if (!f) {
      return (function* _preorderIterator(node) {
        if (node !== null) {
          yield node.value;
          yield* _preorderIterator(node.left);
          yield* _preorderIterator(node.right);
        }
      }(this._root));
    }

    function _preorder(node) {
      if (node !== null) {
        f(node.value);
        _preorder(node.left);
        _preorder(node.right);
      }
    }
    _preorder(this._root);
  }

  /**
   * Returns postorder iterator.
   * @param {Function} [f] - If f is given, execute f by postorder.
   * @returns {(generator|undefined)} Tree postorder iterator. If f if given, not return.
   */
  // eslint-disable-next-line consistent-return
  postorder(f) {
    if (!f) {
      return (function* _postorderIterator(node) {
        if (node !== null) {
          yield* _postorderIterator(node.left);
          yield* _postorderIterator(node.right);
          yield node.value;
        }
      }(this._root));
    }

    function _postorder(node) {
      if (node !== null) {
        _postorder(node.left);
        _postorder(node.right);
        f(node.value);
      }
    }
    _postorder(this._root);
  }

  /**
   * Returns breadth first iterator.
   * @param {Function} [f] - If f is given, execute f by breadth first.
   * @returns {(generator|undefined)} Tree breadth first iterator. If f if given, not return.
   */
  // eslint-disable-next-line consistent-return
  breadthFirst(f) {
    if (!f) {
      return (function* _breadthFirstIterator(root) {
        const queue = new Queue();
        queue.enqueue(root);
        while (queue.size() > 0) {
          const now = queue.dequeue();
          if (now !== undefined && now !== null) {
            yield now.value;
            queue.enqueue(now.left);
            queue.enqueue(now.right);
          }
        }
      }(this._root));
    }

    function _breadthFirst(root) {
      const queue = new Queue();
      queue.enqueue(root);
      while (queue.size() > 0) {
        const now = queue.dequeue();
        if (now !== undefined && now !== null) {
          f(now.value);
          queue.enqueue(now.left);
          queue.enqueue(now.right);
        }
      }
    }
    _breadthFirst(this._root);
  }
}

module.exports = BinarySearchTree;


/***/ })
/******/ ]);
});
//# sourceMappingURL=sangja.map