using System;
using System.Collections;
using System.Diagnostics;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using miew.ReadOnly;
using miew.Tokenization;
using miew.Concurrency;
using miew.Enumerable;
namespace agree
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
abstract public unsafe partial class ChartBase : ISysObj, IEnumerable<IParseObj>
{
static int next_chart_id = 0;
readonly public ParseControl ctrl;
readonly int chart_id;
readonly protected int c_columns;
protected ChartCell[][] chart;
Span entire_span;
//public int g_dseq = 1;
/// a global interlocking sequence between the edge subscription mechanism (used by active edges) and the chart cell
/// contents (passive edges). Valid sequence numbers are even numbers; a non-zero LSB indicates that (id-1)
/// has been claimed and is in the process of being inserted into the respective list, which should be a short
/// enough duration to spin-wait on.
int next_edge_id = 2;
public void StampSequence(IAtomicSequence obj)
{
while (true)
{
int ci = next_edge_id;
if ((ci & 1) == 0 && Interlocked.CompareExchange(ref next_edge_id, ci + 1, ci) == ci)
{
obj.SetSequenceId(ci);
/// can rely on the _next_ CMPXCHG of the global sequence counter to ensure that the write we just
/// did to the object is flushed prior to the possibility of that next counter value being issued and
/// published. Hence a full fence right here should not be required.
next_edge_id = ci + 2;
obj.SetStateNew();
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
internal ChartBase(ParseControl ctrl)
{
this.c_columns = ctrl.la.ChartSize;
if (c_columns == 0)
{
Exception ex_inner = new ArgumentException("Parse chart cannot have zero columns", "c_columns");
throw new TypeInitializationException(this.GetType().FullName, ex_inner);
}
this.ctrl = ctrl;
this.chart_id = Interlocked.Increment(ref next_chart_id);
this.entire_span = new Span(0, (uint)c_columns);
this.chart = new ChartCell[c_columns][];
for (int i = 0; i < c_columns; i++)
{
ChartCell[] cc = chart[i] = new ChartCell[c_columns - i];
for (int j = 0; j < c_columns - i; j++)
cc[j] = new ChartCell(this);
}
}
public void ReleaseChart()
{
this.chart = null;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ChartCell this[Span span]
{
get { return chart[span.StartIndex][span.Length - 1]; }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//public IEnumerable<IParseObj> GetCellEdges(int i_col, int c_span)
//{
// return chart[i_col][c_span - 1];
//}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int ColumnCount { get { return c_columns; } }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public Span EntireSpan { get { return entire_span; } }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public String InputText { get { return ctrl.InputText; } }
internal ConcurrentList<PassiveEdge.Completed> _completed_edges = new ConcurrentList<PassiveEdge.Completed>();
public IEnumerable<PassiveEdge.Completed> CompletedEdges
{
get
{
if (ctrl.parser_config.packing == Config.Parser.PackingOpts.None)
return _completed_edges;
return _completed_edges.Where(p =>
{
int q = p.State;
if ((q & SequenceControl.stb_Hold) > 0)
throw new Exception();
if (q == SequenceControl.ACTIVE)
return true;
return false;
});
}
}
IReadOnlyDictionary<String, ISysObj> _completed_parses_dict = null;
public IReadOnlyDictionary<String, ISysObj> SysObjChildren
{
get
{
if (_completed_parses_dict == null)
_completed_parses_dict = _completed_edges.ToReadOnlyDictionary(p => p.SysObjName, p => (ISysObj)p);
return _completed_parses_dict;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// enumerator for all edges in the chart. this is also the type of enumerator for the chart itself.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public IEnumerator<IParseObj> GetEnumerator() { return new ChartCell._enum_all_edges(this); }
IEnumerator IEnumerable.GetEnumerator() { return new ChartCell._enum_all_edges(this); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// each cell of the chart is a concurrent list of objects which implement the IParseObj interface
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public sealed class ChartCell : IEnumerable<IParseObj>
{
IParseObj m_first = null;
IParseObj m_last = null;
ChartBase m_cb;
public ChartCell(ChartBase cb)
{
m_cb = cb;
}
public void Add(IParseObj po)
{
Debug.Assert(po.State == default(byte));
po.SetStateRaw(SequenceControl.PENDING);
if (m_first != null || Interlocked.CompareExchange(ref m_first, po, null) != null)
{
IParseObj ml = m_last ?? m_first;
while (ml.Next != null || !ml.TrySetTail(po))
ml = ml.Next;
m_last = ml;
}
m_cb.StampSequence(po);
}
public struct _enum : IEnumerator<IParseObj>
{
ChartCell cc;
IParseObj po;
public _enum(ChartCell cc)
{
this.cc = cc;
this.po = null;
}
public bool MoveNext()
{
return (po = po == null ? cc.m_first : po.Next) != null;
}
public void Reset() { this.po = null; }
public IParseObj Current
{
get { return po; }
set { po = value; }
}
object IEnumerator.Current { get { return po; } }
public void Dispose() { }
};
public struct _enum_all_edges : IEnumerator<IParseObj>
{
ChartBase cb;
IParseObj po;
int i_col, i_span;
public _enum_all_edges(ChartBase cb)
{
Debug.Assert(cb.ctrl.f_parse_phase_complete);
this.cb = cb;
this.po = null;
this.i_col = this.i_span = 0;
}
public void Reset()
{
i_col = i_span = 0;
po = null;
}
public bool MoveNext()
{
while (true)
{
while ((po = po == null ? cb.chart[i_col][i_span].m_first : po.Next) != null)
if (po.IsActive())
return true;
if (++i_span >= cb.c_columns - i_col)
{
if (++i_col >= cb.c_columns)
return false;
i_span = 0;
}
}
}
public IParseObj Current { get { return po; } }
object IEnumerator.Current { get { return Current; } }
public void Dispose() { }
};
public struct _multi_cell_enum : IEnumerator<IParseObj>
{
int i, i_incr, j, j_incr;
ChartCell cc;
IParseObj po;
ChartCell[][] rgcc;
public _multi_cell_enum(ChartBase chart, int i_min, int i_incr, int j_min, int j_incr)
{
this.i = i_min;
this.i_incr = i_incr;
this.j = j_min;
this.j_incr = j_incr;
this.rgcc = chart.chart;
this.cc = rgcc[i][j];
this.po = null;
}
public bool MoveNext()
{
while ((po = po == null ? cc.m_first : po.Next) == null)
{
if ((j += j_incr) < 0 || (i += i_incr) < 0 || i >= rgcc.Length)
{
this.rgcc = null;
return false;
}
ChartCell[] arr = rgcc[i];
if (j >= arr.Length)
{
this.rgcc = null;
return false;
}
cc = arr[j];
po = null;
}
return true;
}
public IParseObj Current { get { return po; } }
object IEnumerator.Current { get { return po; } }
public void Reset() { throw new NotImplementedException(); }
public void Dispose() { }
};
public IEnumerator<IParseObj> GetEnumerator() { return new _enum(this); }
IEnumerator IEnumerable.GetEnumerator() { return new _enum(this); }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public String SysObjName
{
get { return String.Format("pc{0}", chart_id); }
}
public string SysObjDescription
{
get { return InputText ?? SysObjName; }
}
public ISysObj SysObjParent
{
get { return ctrl.g; }
}
};
}