/// <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];
 }