Advertisement
Isti115

MultiKeyMap

Mar 29th, 2017
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const MultiKeyMap = (() => {
  2.   const symbols = {
  3.     checkKeyLength: Symbol('checkKeyLength'),
  4.     keyCount: Symbol('keyCount'),
  5.     data: Symbol('data')
  6.   }
  7.  
  8.   /**
  9.    * @throws {NotEnoughKeys} When the list of keys given to a method is too short.
  10.    * @throws {TooManyKeys} When the list of keys given to a method is too long.
  11.    * @throws {KeyIsNotPresent} When no value was found in the get method.
  12.    */
  13.   class MultiKeyMap {
  14.     /**
  15.      * Constructs a new map with the given number of keys.
  16.      * @param {number} n The number of keys.
  17.      */
  18.     constructor (n) {
  19.       this[symbols.keyCount] = n
  20.       this[symbols.data] = {}
  21.     }
  22.  
  23.     [symbols.checkKeyLength] (n) {
  24.       if (n < this[symbols.keyCount]) {
  25.         throw Error(`Not enough keys. Expected ${this[symbols.keyCount]}, received ${n}.`)
  26.       }
  27.  
  28.       if (n > this[symbols.keyCount]) {
  29.         throw Error(`Too many keys. Expected ${this[symbols.keyCount]}, received ${n}.`)
  30.       }
  31.     }
  32.  
  33.     /**
  34.      * Assigns the specified value to the given keys.
  35.      * @param keys {string[]} An array of length n containing stringifiable items where n is the number of keys in the map.
  36.      * @param value {*} The actual value.
  37.      */
  38.     set (keys, value) {
  39.       keys = JSON.parse(JSON.stringify(keys))
  40.  
  41.       this[symbols.checkKeyLength](keys.length)
  42.  
  43.       let currentData = this[symbols.data]
  44.  
  45.       while (keys.length > 1) {
  46.         const currentKey = keys.shift()
  47.  
  48.         if (!(currentKey in currentData)) {
  49.           currentData[currentKey] = {}
  50.         }
  51.  
  52.         currentData = currentData[currentKey]
  53.       }
  54.  
  55.       const currentKey = keys.shift()
  56.       currentData[currentKey] = value
  57.     }
  58.  
  59.     /**
  60.      * Checks whether the map contains any value assigned to the given keys.
  61.      * @param keys {string[]} An array of length n containing stringifiable items where n is the number of keys in the map.
  62.      *
  63.      * @return {boolean} Whether an assigned value was found or not.
  64.      */
  65.     contains (keys) {
  66.       keys = JSON.parse(JSON.stringify(keys))
  67.  
  68.       this[symbols.checkKeyLength](keys.length)
  69.  
  70.       let currentData = this[symbols.data]
  71.  
  72.       while (keys.length > 1) {
  73.         const currentKey = keys.shift()
  74.  
  75.         if (!(currentKey in currentData)) {
  76.           return false
  77.         }
  78.  
  79.         currentData = currentData[currentKey]
  80.       }
  81.  
  82.       const currentKey = keys.shift()
  83.       return (currentKey in currentData)
  84.     }
  85.  
  86.     /**
  87.      * Gets the value stored behind the given keys.
  88.      * @param keys {string[]} An array of length n containing stringifiable items where n is the number of keys in the map.
  89.      *
  90.      * @return {*} The requested value.
  91.      */
  92.     get (keys) {
  93.       keys = JSON.parse(JSON.stringify(keys))
  94.  
  95.       const keyString = keys.join(' - ')
  96.  
  97.       this[symbols.checkKeyLength](keys.length)
  98.  
  99.       let currentData = this[symbols.data]
  100.  
  101.       while (keys.length > 1) {
  102.         const currentKey = keys.shift()
  103.  
  104.         if (!(currentKey in currentData)) {
  105.           throw Error(`Key is not present in map. (${keyString})`)
  106.         }
  107.  
  108.         currentData = currentData[currentKey]
  109.       }
  110.  
  111.       const currentKey = keys.shift()
  112.  
  113.       if (!(currentKey in currentData)) {
  114.         throw Error(`Key is not present in map. (${keyString})`)
  115.       }
  116.  
  117.       return currentData[currentKey]
  118.     }
  119.  
  120.     /**
  121.      * Returns a stringified JSON representation of the map.
  122.      * @return {string} Stringified JSON representation of the map.
  123.      */
  124.     stringify () {
  125.       return JSON.stringify(this[symbols.data], null, 2)
  126.     }
  127.   }
  128.  
  129.   return MultiKeyMap
  130. })()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement