|
#region copyright
// Copyright Andrew Rafas 2012.
// Distributed under the Eclipse Public License, Version 1.0.
// (See accompanying file LICENSE.txt or
// copy at http://www.eclipse.org/legal/epl-v10.html)
#endregion
using System;
using System.Collections.Generic;
namespace CSFP.Memoize
{
public interface ISource
{
/// <summary>
/// Returns true if the value can be calculated, or already has been calculated.
/// When returns false, Value will throw on access (if we are an IValue[T]).
/// </summary>
bool IsReady { get; }
void AddDependent(IDependent dependency, int key);
}
public interface IValue<T> : ISource
{
/// <summary>
/// Returns the expression's value when IsReady == true. It either returns the cached
/// value or calculates (and possibly caches) a fresh one.
/// </summary>
T Value { get; }
}
public interface IDependent
{
void Notify(int readyChange, int key);
}
public abstract class DependentList
{
// we can just substract these values from _notReadyCount
public const int BecomeNotReady = -1; // which implies that all dependencies has to invalidate the cached value
public const int ValueChanged = 0; // was Ready and remained Ready but all dependencies has to invalidate the cached value
public const int BecomeReady = +1; // which implies that all dependencies has to invalidate the cached value
public abstract void NotifyAll(int readyChange);
public abstract DependentList Add(DepKey dk);
}
public struct DepKey
{
public readonly IDependent Item1;
public readonly int Item2;
public DepKey(IDependent item1, int item2)
{
Item1 = item1;
Item2 = item2;
}
}
public class MultiDependentList : DependentList
{
DepKey[] _list = new DepKey[4];
int _count;
public override void NotifyAll(int readyChange)
{
var list = _list;
for (int i = 0; i < _count; ++i) {
var d = list[i];
d.Item1.Notify(readyChange, d.Item2);
}
}
public override DependentList Add(DepKey dk)
{
if (_count >= _list.Length) {
var newlist = new DepKey[_list.Length * 2];
Array.Copy(_list, newlist, _list.Length);
_list = newlist;
}
_list[_count] = dk;
++_count;
return this;
}
}
public class SingleDependentList : DependentList
{
DepKey d;
public SingleDependentList(DepKey d)
{
this.d = d;
}
public override void NotifyAll(int readyChange)
{
d.Item1.Notify(readyChange, d.Item2);
}
public override DependentList Add(DepKey dk)
{
var l = new MultiDependentList();
l.Add(d);
return l.Add(dk);
}
}
public class EmptyDependentList : DependentList
{
public static EmptyDependentList Instance = new EmptyDependentList();
public override void NotifyAll(int readyChange)
{
}
public override DependentList Add(DepKey dk)
{
return new SingleDependentList(dk);
}
}
public static class Helper
{
#if DEBUG
static Dictionary<object, string> _debugInfo = new Dictionary<object, string>();
static Dictionary<object, string> _shortDebugInfo = new Dictionary<object, string>();
public static long CalculationCount = 0;
public static long NotificationCount = 0;
static string debugize(object o, object def)
{
if (def == null)
def = o;
string info;
if (_shortDebugInfo.TryGetValue(o, out info))
return info;
if (_debugInfo.TryGetValue(o, out info))
return info;
return def.ToString();
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void Log(string format, params object[] values)
{
for (int i = 0; i < values.Length; ++i) {
string info;
if (_debugInfo.TryGetValue(values[i], out info))
values[i] = info;
}
string line = string.Format(format, values);
System.Diagnostics.Trace.WriteLine(line);
}
/// <summary>
/// Sets up the debuginfo which is used for tracing calculations.
/// </summary>
[System.Diagnostics.Conditional("DEBUG")]
public static void Debug(object o, string info, string shortName = null)
{
if (o is Dependent) {
var d = (Dependent)o;
var sb = new System.Text.StringBuilder();
sb.AppendFormat("{0}(", info);
for (int i = 0; i < d.SourceList.Length; ++i) {
if (i != 0)
sb.Append(", ");
sb.Append(debugize(d.SourceList[i], "?"));
}
sb.Append(")");
_debugInfo[o] = sb.ToString();
} else {
_debugInfo[o] = info;
}
if (shortName != null)
_shortDebugInfo[o] = shortName;
}
#else
public static void Debug(object o, string info, string shortName = null) { }
#endif
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I am a senior software developer with almost 20 years of experience. I have extensive knowledge of C#, C++ and Assembly languages, working mainly on Windows and embedded systems. Outside of work I am interested in a wider variety of technologies, including learning 20 programming languages, developing Linux kernel drivers or advocating Functional Programming recently.