using DTT.Utils.Exceptions;
using System;
using System.Collections.Generic;
namespace DTT.Utils.Optimization
{
///
/// A dictionary variant that allows for constructors to be added to
/// delay the initial creation of a struct value to where when it is needed
/// using the wrapper struct.
///
/// The type of key.
/// The type of the value.
public class LazyValueDictionary : LazyDictionaryBase where TValue : struct
{
///
/// Wraps the item value and its constructor, providing
/// a one time initialization upon retrieval.
///
private class Container
{
///
/// The cached item value. It is wrapped inside a
/// struct to check whether it is initialized or not.
///
private TValue? _nullableValue;
///
/// The constructor with which to initialize the value.
///
private readonly Func _constructor;
///
/// The accessor to the cached item value. It returns the value of the nullable wrapper
/// if it has it. Otherwise it will assign the value using the constructor and return
/// the resulting value.
///
public TValue Value => _nullableValue ?? (_nullableValue = _constructor()).Value;
///
/// Creates a new instance, storing the given constructor.
///
/// The constructor with which to initialize the value.
public Container(Func constructor) => _constructor = constructor;
}
///
/// Contains the keys with their value in their respective containers.
///
private readonly Dictionary _values = new Dictionary();
///
/// Adds a new item to the dictionary with its respective constructor.
///
/// The key for the value.
///
/// The constructor with which to initialize the value.
///
public void Add(TKey key, Func constructor)
{
if (key == null)
throw new LazyDictionaryException("Name of property is null");
if (constructor == null)
throw new LazyDictionaryException($"Constructor of {key} is null.");
_values.Add(key, new Container(constructor));
}
///
/// Should return the item value based on the given key.
///
/// The key to get the value for.
/// The item value.
protected override TValue GetValue(TKey key) => _values[key].Value;
}
}