"use strict"
var __createBinding =
  (this && this.__createBinding) ||
  (Object.create
    ? function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        Object.defineProperty(o, k2, {
          enumerable: true,
          get: function () {
            return m[k]
          }
        })
      }
    : function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        o[k2] = m[k]
      })
var __setModuleDefault =
  (this && this.__setModuleDefault) ||
  (Object.create
    ? function (o, v) {
        Object.defineProperty(o, "default", { enumerable: true, value: v })
      }
    : function (o, v) {
        o["default"] = v
      })
var __importStar =
  (this && this.__importStar) ||
  function (mod) {
    if (mod && mod.__esModule) return mod
    var result = {}
    if (mod != null)
      for (var k in mod)
        if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
          __createBinding(result, mod, k)
    __setModuleDefault(result, mod)
    return result
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.modify =
  exports.modify_ =
  exports.update =
  exports.update_ =
  exports.size =
  exports.remove =
  exports.remove_ =
  exports.set =
  exports.set_ =
  exports.get =
  exports.get_ =
  exports.make =
  exports.HashMap =
  exports.HashMapTypeId =
    void 0
const tracing_1 = __importStar(require("../../../Tracing"))
const tracing_2 = __importStar(require("../../../Tracing"))
const fileName_1 = "(@effect-ts/system): _src/Collections/Mutable/HashMap/index.ts"
const I = __importStar(require("../../../Iterable"))
const O = __importStar(require("../../../Option"))
const St = __importStar(require("../../../Structural"))
const AtomicNumber_1 = require("../../../Support/AtomicNumber")
exports.HashMapTypeId = Symbol()
class Node {
  constructor(k, v, next) {
    this.k = k
    this.v = v
    this.next = next
  }
  [Symbol.iterator]() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    let c = this
    let n = 0
    return {
      next: () => {
        if (c) {
          const kv = [c.k, c.v]
          c = c.next
          n++
          return {
            value: kv,
            done: false
          }
        } else {
          return {
            value: n,
            done: true
          }
        }
      }
    }
  }
}
/**
 * A Mutable HashMap
 */
class HashMap {
  constructor() {
    this._typeId = exports.HashMapTypeId
    this.backingMap = new Map()
    this.length = new AtomicNumber_1.AtomicNumber(0)
  }
  get(k) {
    const hash = St.hash(k)
    const arr = this.backingMap.get(hash)
    if (typeof arr === "undefined") {
      return O.none
    }
    let c = arr
    while (c) {
      if (St.equals(k, c.k)) {
        return O.some(c.v)
      }
      c = c.next
    }
    return O.none
  }
  remove(k) {
    const hash = St.hash(k)
    const arr = this.backingMap.get(hash)
    if (typeof arr === "undefined") {
      return this
    }
    if (St.equals(k, arr.k)) {
      if (typeof arr.next !== "undefined") {
        this.backingMap.set(hash, arr.next)
      } else {
        this.backingMap.delete(hash)
      }
      this.length.decrementAndGet()
      return this
    }
    let next = arr.next
    let curr = arr
    while (next) {
      if (St.equals(k, next.k)) {
        curr.next = next.next
        this.length.decrementAndGet()
        return this
      }
      curr = next
      next = next.next
    }
    return this
  }
  set(k, v) {
    const hash = St.hash(k)
    const arr = this.backingMap.get(hash)
    if (typeof arr === "undefined") {
      this.backingMap.set(hash, new Node(k, v))
      this.length.incrementAndGet()
      return this
    }
    let c = arr
    let l = arr
    while (c) {
      if (St.equals(k, c.k)) {
        c.v = v
        return this
      }
      l = c
      c = c.next
    }
    this.length.incrementAndGet()
    l.next = new Node(k, v)
    return this
  }
  update(k, f) {
    const hash = St.hash(k)
    const arr = this.backingMap.get(hash)
    if (typeof arr === "undefined") {
      return this
    }
    let c = arr
    while (c) {
      if (St.equals(k, c.k)) {
        c.v = f(c.v)
        return this
      }
      c = c.next
    }
    return this
  }
  [Symbol.iterator]() {
    return I.chain_(this.backingMap, ([, _]) => _)[Symbol.iterator]()
  }
}
exports.HashMap = HashMap
/**
 * Creates a new map
 */
function make() {
  return new HashMap()
}
exports.make = make
/**
 * Lookup the value for `key` in `map` using internal hash function.
 */
function get_(map, key) {
  return map.get(key)
}
exports.get_ = get_
/**
 * Lookup the value for `key` in `map` using internal hash function.
 *
 * @dataFirst get_
 */
function get(key) {
  return (map) => get_(map, key)
}
exports.get = get
/**
 * Store `value` for `key` in `map` using internal hash function.
 */
function set_(map, key, value) {
  return map.set(key, value)
}
exports.set_ = set_
/**
 * Store `value` for `key` in `map` using internal hash function.
 *
 * @dataFirst set_
 */
function set(key, value) {
  return (map) => set_(map, key, value)
}
exports.set = set
/**
 * Remove the entry for `key` in `map` using internal hash.
 */
function remove_(map, key) {
  return map.remove(key)
}
exports.remove_ = remove_
/**
 * Remove the entry for `key` in `map` using internal hash.
 *
 * @dataFirst remove_
 */
function remove(key) {
  return (map) => remove_(map, key)
}
exports.remove = remove
/**
 * Calculate the number of key/value pairs in a map
 */
function size(map) {
  return map.length.get
}
exports.size = size
/**
 * Update a value if exists
 */
function update_(map, key, f) {
  return map.update(key, f)
}
exports.update_ = update_
/**
 * Update a value if exists
 *
 * @dataFirst update_
 */
function update(key, f) {
  return (map) => update_(map, key, f)
}
exports.update = update
/**
 * Alter the value stored for `key` in `map` using function `f` using internal hash function.
 *
 *  `f` is invoked with the current value for `k` if it exists,
 * or no arguments if no such value exists.
 *
 * `modify` will always either update or insert a value into the map.
 * Returns a map with the modified value. Does not alter `map`.
 */
function modify_(map, key, f) {
  const v = f(map.get(key))
  if (O.isSome(v)) {
    map.set(key, v.value)
  } else {
    map.remove(key)
  }
  return map
}
exports.modify_ = modify_
/**
 * Alter the value stored for `key` in `map` using function `f` using internal hash function.
 *
 *  `f` is invoked with the current value for `k` if it exists,
 * or no arguments if no such value exists.
 *
 * `modify` will always either update or insert a value into the map.
 * Returns a map with the modified value. Does not alter `map`.
 *
 * @dataFirst modify_
 */
function modify(key, f) {
  return (map) => modify_(map, key, f)
}
exports.modify = modify
//# sourceMappingURL=index.js.map
