/// <summary> /// Check if something exists at a specified location and return it. /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <param name="value">value if found at specified location</param> /// <returns>bool specifying whether something was found or not</returns> public bool IfContainsGet(byte[] key, out T value) { DirectDictionaryLayer <T, Container> current = this; for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { value = default(T); return(false); } } if (current.ValueContainer != null) { value = current.ValueContainer.Value; return(true); } else { value = default(T); return(false); } }
/// <summary> /// Merges two structures together. Passed layer will overwrite overlapping locations existing in both. /// </summary> /// <param name="mergeLayer">layer to merge into this one</param> public void Merge(DirectDictionaryLayer <T, Container> mergeLayer) { mergeLayer.ExecuteOnAllItems((o, k) => { Set(k, o); }); }
/// <summary> /// Get the layer object at the specified location /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <returns>Layer at location</returns> public DirectDictionaryLayer <T, Container> GetLayer(byte[] key) { DirectDictionaryLayer <T, Container> current = this; for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { lock (current) { //Check again to make sure you are not overwriting another thread's work if (current.Items[key[i]] == null) { current.Items[key[i]] = new DirectDictionaryLayer <T, Container>(); } } current = current.Items[key[i]]; } } return(current); }
/// <summary> /// Set a specified location with a value /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <param name="data">item to store at this location</param> public void Set(byte[] key, T data) { DirectDictionaryLayer <T, Container> current = this; if (key != null) { for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { lock (current) { //Check again to make sure you are not overwriting another thread's work if (current.Items[key[i]] == null) { current.Items[key[i]] = new DirectDictionaryLayer <T, Container>(); } } current = current.Items[key[i]]; } } } current.ValueContainer = new Container() { Value = data }; }
/// <summary> /// Get value stored at location /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <returns>Value stored at location</returns> public T Get(byte[] key) { DirectDictionaryLayer <T, Container> current = this; //Any recursion can be done in a while loop and while loops can become for loops when you know how deep you need to go. for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { throw new KeyNotFoundException(); } } if (current.ValueContainer != null) { return(current.ValueContainer.Value); } else { throw new KeyNotFoundException(); } }
/// <summary> /// Chect if a location exists /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <returns>Exists?</returns> public bool Contains(byte[] key) { DirectDictionaryLayer <T, Container> current = this; for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { return(false); } } if (current.ValueContainer != null) { return(true); } else { return(false); } }
/// <summary> /// Get a value at a specified location or set it if it's empty /// </summary> /// <param name="key">location key (Must be nibbles)</param> /// <param name="getNewFunc">function used to set location if it's empty</param> /// <returns>Value that was get or set</returns> public T GetOrSet(byte[] key, Func <T> getNewFunc) { DirectDictionaryLayer <T, Container> current = this; bool found = true; for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { found = false; lock (current) { if (current.Items[key[i]] == null) { current.Items[key[i]] = new DirectDictionaryLayer <T, Container>(); } } current = current.Items[key[i]]; } } if (!found) { lock (current) { if (current.ValueContainer == null) { current.ValueContainer = new Container() { Value = getNewFunc() }; } else { return(current.ValueContainer.Value); } } } if (current.ValueContainer == null) { lock (current) { current.ValueContainer = new Container() { Value = getNewFunc() }; } } return(current.ValueContainer.Value); }
/// <summary> /// Delete a value stored at a specified location /// </summary> /// <param name="key">location key (Must be nibbles)</param> public void Delete(byte[] key) { DirectDictionaryLayer <T, Container> current = this; bool found = true; for (int i = 0; i < key.Length; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { found = false; break; } } if (found) { lock (current) { //don't check again because deleting is deleting current.ValueContainer = null; } } //reclaim memory if possible for (int i = key.Length - 1; i >= 0; --i) { byte[] newKey = new byte[i + 1]; Array.Copy(key, newKey, i + 1); DirectDictionaryLayer <T, Container> layerCheck = GetLayer(key); if (ShouldDelete(layerCheck)) { if (newKey.Length > 1) { byte[] deleteKey = new byte[newKey.Length - 1]; Array.Copy(newKey, deleteKey, deleteKey.Length); DirectDictionaryLayer <T, Container> deleteFromLayer = GetLayer(deleteKey); deleteFromLayer.Items[newKey[newKey.Length - 1]] = null; } } else { break; } } }
private bool ShouldDelete(DirectDictionaryLayer <T, Container> layer) { if (layer.ValueContainer != null) { return(false); } bool shouldDelete = true; for (int i = 0; i < layer.Items.Length; ++i) { if (layer.Items[i] != null) { shouldDelete = false; break; } } return(shouldDelete); }
private DirectDictionaryLayer <T, Container> GetKeyFragmentRoot(byte[] keyFragment) { int level = 0; DirectDictionaryLayer <T, Container> current = this; while (level < keyFragment.Length) { if (current.Items[keyFragment[level]] == null) { return(null); } else { current = current.Items[keyFragment[level]]; } ++level; } return(current); }
/// <summary> /// Set the layer object a the specified location. /// And yes this data structure can loop back on itself if you set layers to refer back to layers higher up in the tree. /// </summary> /// <param name="key">location to set layer (Must be nibbles)</param> /// <param name="layer">layer object to set at location</param> /// <param name="swap">Whether to take move existing layer's children over to the newly set one.</param> public void SetLayer(byte[] key, DirectDictionaryLayer <T, Container> layer, bool swap = false) { DirectDictionaryLayer <T, Container> current = this; for (int i = 0; i < key.Length - 1; ++i) { if (current.Items[key[i]] != null) { current = current.Items[key[i]]; } else { lock (current) { //Check again to make sure you are not overwriting another thread's work if (current.Items[key[i]] == null) { current.Items[key[i]] = new DirectDictionaryLayer <T, Container>(); } } current = current.Items[key[i]]; } } if (key.Length > 0) { lock (current) { byte last = key[key.Length - 1]; if (swap && current.Items[last] != null) { DirectDictionaryLayer <T, Container> swapTarget = current.Items[last]; current.Items[last] = layer; Array.Copy(swapTarget.Items, layer.Items, 16); } else { current.Items[last] = layer; } } } }
/// <summary> /// Delete a value stored at specified location without cleaning up the structure. (Faster but leaves memory in use) /// </summary> /// <param name="key">location key (Must be nibbles)</param> public void DeleteWithoutShrink(byte[] key) { int level = 0; DirectDictionaryLayer <T, Container> current = this; while (level < key.Length) { if (current.Items[key[level]] == null) { return; } else { current = current.Items[key[level]]; } ++level; } lock (current) { current.ValueContainer = null; } }
public void SetLayer(string key, DirectDictionaryLayer <T, Container> layer, bool swap = false) { byte[] bytes = key.ConvertToNibbles(); SetLayer(bytes, layer, swap); }
public void SetLayer <K>(K key, DirectDictionaryLayer <T, Container> layer, bool swap = false) where K : struct { byte[] bytes = GetBytes <K>(key).SplitNibbles(); SetLayer(bytes, layer, swap); }
public DirectDictionaryLayer() { //16 is a good balance between performance and memory cost. Items = new DirectDictionaryLayer <T, Container> [16]; }