/* $Id$ * * Project: Swicli.Library - Two Way Interface for .NET and MONO to SWI-Prolog * Author: Douglas R. Miles * E-mail: logicmoo@gmail.com * WWW: http://www.logicmoo.com * Copyright (C): 2010-2012 LogicMOO Developement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *********************************************************/ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Threading; using SbsSW.SwiPlCs; namespace Swicli.Library { public partial class PrologCLR { static public IDictionary CreatePrologBackedDictionary(PlTerm pred) { string p = PredicateName(pred); return new PrologBackedDictionary( PredicateModule(pred), p + "_get", CreatePrologBackedCollection(pred), p + "_set", p + "_remove", p + "_clear"); } static public ICollection CreatePrologBackedCollection(PlTerm pred) { string p = PredicateName(pred); return new PrologBackedCollection( PredicateModule(pred), p + "_get", p + "_add", p + "_remove", p + "_clear"); } [PrologVisible] static public bool cliTestPbd(PlTerm pred, PlTerm counted) { var id = CreatePrologBackedDictionary(pred); string s = String.Empty; var enumer = id.GetEnumerator(); while (enumer.MoveNext()) { var o = enumer.Current; s += String.Format("{0}={1},", o.Key, o.Value); } counted.UnifyAtom(s); return true; } [PrologVisible] static public bool cliTestPbdt(PlTerm pred, PlTerm counted) { var id = CreatePrologBackedDictionary(pred); string s = String.Empty; AutoResetEvent are = new AutoResetEvent(false); (new Thread(() => { var enumer = id.GetEnumerator(); while (enumer.MoveNext()) { var o = enumer.Current; s += String.Format("{0}={1},", o.Key, o.Value); } are.Set(); })).Start(); are.WaitOne(); counted.UnifyAtom(s); return true; } [PrologVisible] static public bool cliTestPbct(PlTerm pred, PlTerm counted) { var id = CreatePrologBackedCollection(pred); string s = String.Empty; AutoResetEvent are = new AutoResetEvent(false); (new Thread(() => { var enumer = id.GetEnumerator(); while (enumer.MoveNext()) { var o = enumer.Current; s += String.Format("{0},", o); } are.Set(); })).Start(); are.WaitOne(); counted.UnifyAtom(s); return true; } [PrologVisible] static public bool cliTestPbc(PlTerm pred, PlTerm counted) { var id = CreatePrologBackedCollection(pred); string s = String.Empty; IEnumerator enumer = id.GetEnumerator(); while (enumer.MoveNext()) { s += String.Format("{0},", enumer.Current); } counted.UnifyAtom(s); return true; } } public abstract class PrologBacked { public void InForiegnFrame(Action action) { PrologCLR.RegisterCurrentThread(); uint fid = libpl.PL_open_foreign_frame(); try { action(); } finally { // if (fid > 0) libpl.PL_close_foreign_frame(fid); } } public static bool PlCall(string module, string querypred, PlTermV termV) { return PrologCLR.PlCall(module, querypred, termV); } public static PlTerm KeyToTerm(TKey key) { if (key.Equals(default(TValue))) return PlTerm.PlVar(); return PrologCLR.ToProlog(key); } public static PlTerm ValueToTerm(TValue value) { if (value.Equals(default(TValue))) return PlTerm.PlVar(); return PrologCLR.ToProlog(value); } public static PlTermV TermVOf(KeyValuePair item) { return new PlTermV(KeyToTerm(item.Key), ValueToTerm(item.Value)); } protected Exception NewNotImplementedException() { throw new NotImplementedException("NewNotImplementedException"); } public abstract string ToDebugString(); } public class PrologBackedDictionary : PrologBacked, IDictionary { private readonly string _module = null;//"user"; private readonly string _getvalue; private ICollection Keyz; private readonly Type valueType; private string _assertPred; private string _retractPred; private string _retractall; private Type keyType; public PrologBackedDictionary(string module, string get_value, ICollection keyz, string assertPred, string retractPred, string retractall) { _module = module ?? "user"; _getvalue = get_value; Keyz = keyz; _assertPred = assertPred; _retractPred = retractPred; _retractall = retractall; keyType = typeof(TKey); valueType = typeof(TValue); } #region Implementation of IEnumerable /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// 1 public IEnumerator> GetEnumerator() { PrologCLR.RegisterCurrentThread(); return new PrologBackedDictionaryEnumerator(this); } public Dictionary Copy() { var copy = new Dictionary(); foreach (var e in this) { copy.Add(e.Key,e.Value); } return copy; } public class PrologBackedDictionaryEnumerator : IEnumerator> { private readonly PrologBackedDictionary _dictionary; private uint fframe = 0; private PlTermV termV; private PlQuery plQuery; public PrologBackedDictionaryEnumerator(PrologBackedDictionary dictionary) { _dictionary = dictionary; Reset(); } #region Implementation of IDisposable /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// 2 public void Dispose() { if (plQuery != null) plQuery.Dispose(); plQuery = null; if (fframe != 0) libpl.PL_close_foreign_frame(fframe); fframe = 0; } #endregion #region Implementation of IEnumerator /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// The collection was modified after the enumerator was created. /// 2 public bool MoveNext() { if (!plQuery.NextSolution()) { Dispose(); return false; } return true; } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// The collection was modified after the enumerator was created. /// 2 public void Reset() { Dispose(); //fframe = libpl.PL_open_foreign_frame(); termV = new PlTermV(2); plQuery = new PlQuery(_dictionary._module, _dictionary._getvalue, termV); } /// /// Gets the element in the collection at the current position of the enumerator. /// /// /// The element in the collection at the current position of the enumerator. /// public KeyValuePair Current { get { return new KeyValuePair( (TKey)PrologCLR.CastTerm(plQuery.Args[0], _dictionary.keyType), (TValue)PrologCLR.CastTerm(plQuery.Args[1], _dictionary.valueType)); } } /// /// Gets the current element in the collection. /// /// /// The current element in the collection. /// /// The enumerator is positioned before the first element of the collection or after the last element. /// 2 object IEnumerator.Current { get { return Current; } } #endregion } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// /// 2 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of ICollection> /// /// Adds an item to the . /// /// The object to add to the . /// The is read-only. /// public void Add(KeyValuePair item) { if (_assertPred == null) throw new NotSupportedException("add " + this); InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_getvalue, TermVOf(item)); PlCall(_module, _assertPred, new PlTermV(newPlTermV)); }); } /// /// Removes all items from the . /// /// The is read-only. /// public void Clear() { if (_retractall == null) throw new NotSupportedException("clear " + this); InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_getvalue, new PlTermV(2)); PlCall(_module, _retractall, new PlTermV(newPlTermV)); }); } /// /// Determines whether the contains a specific value. /// /// /// true if is found in the ; otherwise, false. /// /// The object to locate in the . /// public bool Contains(KeyValuePair item) { bool found = false; InForiegnFrame(() => { found = PlCall(_module, _getvalue, TermVOf(item)); }); return found; } /// /// Copies the elements of the to an , starting at a particular index. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// is null. /// is less than 0. /// is multidimensional. /// -or- /// is equal to or greater than the length of . /// -or- /// The number of elements in the source is greater than the available space from to the end of the destination . /// -or- /// Type cannot be cast automatically to the type of the destination . /// public void CopyTo(KeyValuePair[] array, int arrayIndex) { throw NewNotImplementedException(); } /// /// Removes the first occurrence of a specific object from the . /// /// /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . /// /// The object to remove from the . /// The is read-only. /// public bool Remove(KeyValuePair item) { bool removed = false; InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_getvalue, TermVOf(item)); removed = PlCall(_module, _retractPred, new PlTermV(newPlTermV)); }); return removed; } /// /// Gets the number of elements contained in the . /// /// /// The number of elements contained in the . /// public int Count { get { return Keyz.Count; } } /// /// Gets a value indicating whether the is read-only. /// /// /// true if the is read-only; otherwise, false. /// public bool IsReadOnly { get { return _retractPred != null; } } #endregion #region Implementation of IDictionary /// /// Determines whether the contains an element with the specified key. /// /// /// true if the contains an element with the key; otherwise, false. /// /// The key to locate in the . /// is null. /// public bool ContainsKey(TKey key) { if (Keyz != null) return Keyz.Contains(key); bool found = false; InForiegnFrame(() => { found = PlCall(_module, _getvalue, new PlTermV(KeyToTerm(key), PlTerm.PlVar())); }); return found; } /// /// Adds an element with the provided key and value to the . /// /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// is null. /// An element with the same key already exists in the . /// The is read-only. /// public void Add(TKey key, TValue value) { Add(new KeyValuePair(key, value)); } /// /// Removes the element with the specified key from the . /// /// /// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original . /// /// The key of the element to remove. /// is null. /// The is read-only. /// public bool Remove(TKey key) { if (Keyz != null) { if (!Keyz.IsReadOnly) return Keyz.Remove(key); } if (_retractPred == null) throw new NotSupportedException("remove " + this); bool removed = false; InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_getvalue, KeyToTerm(key), PlTerm.PlVar()); removed = PlCall(_module, _retractPred, new PlTermV(newPlTermV)); }); return removed; } /// /// Gets the value associated with the specified key. /// /// /// true if the object that implements contains an element with the specified key; otherwise, false. /// /// The key whose value to get. /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. /// is null. /// public bool TryGetValue(TKey key, out TValue value) { TValue value0 = default(TValue); bool res = false; InForiegnFrame(() => { PlTerm plTermPlVar = PlTerm.PlVar(); PlTermV newPlTermV = new PlTermV(KeyToTerm(key), plTermPlVar); res = PlCall(_module, _getvalue, newPlTermV); if (res) { value0 = (TValue)PrologCLR.CastTerm(newPlTermV[1], valueType); } else { } }); value = value0; return res; } /// /// Gets or sets the element with the specified key. /// /// /// The element with the specified key. /// /// The key of the element to get or set. /// is null. /// The property is retrieved and is not found. /// The property is set and the is read-only. /// public TValue this[TKey key] { get { TValue tvalue = default(TValue); InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_getvalue, KeyToTerm(key), PlTerm.PlVar()); bool res = PlCall(_module, _getvalue, new PlTermV(newPlTermV)); if (res) { tvalue = (TValue)PrologCLR.CastTerm(newPlTermV.Arg(1), valueType); } else { // tvalue = default(TValue); } }); return tvalue; } set { Remove(key); Add(new KeyValuePair(key, value)); } } /// /// Gets an containing the keys of the . /// /// /// An containing the keys of the object that implements . /// public ICollection Keys { get { return Keyz; } } /// /// Gets an containing the values in the . /// /// /// An containing the values in the object that implements . /// public ICollection Values { get { throw NewNotImplementedException(); } } #endregion #region Overrides of PrologBacked public override string ToDebugString() { string ds = "" + Count; foreach (var kv in this) { ds += "," + kv.Key + "=" + kv.Value; } return ds; } #endregion } public class PrologBackedCollection : PrologBacked, ICollection, ICollection { private readonly string _module = null;//"user"; private readonly string _querypred; private readonly Type keyType; private readonly Type valueType; private string _assertPred; private string _retractPred; private string _retractall; public PrologBackedCollection(string module, string querypred, string assertPred, string retractPred, string retractall) { _module = module ?? "user"; _querypred = querypred; _assertPred = assertPred; _retractPred = retractPred; _retractall = retractall; keyType = typeof (T); } #region ICollection Members public void Add(T item) { if (_assertPred == null) throw new NotSupportedException("add " + this); InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_querypred, new PlTermV(KeyToTerm(item))); PlCall(_module, _assertPred, new PlTermV(newPlTermV)); }); } public void Clear() { InForiegnFrame(() => { PlTerm newPlTermV = PrologCLR.PlC(_querypred, new PlTermV(1)); PlCall(_module, _retractall, new PlTermV(newPlTermV)); }); } public bool Contains(T item) { bool found = false; InForiegnFrame(() => { found = PlCall(_module, _querypred, new PlTermV(KeyToTerm(item))); }); return found; } public void CopyTo(T[] array, int arrayIndex) { throw NewNotImplementedException(); } /// /// Copies the elements of the to an , starting at a particular index. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// is null. /// is less than zero. /// is multidimensional. /// -or- /// is equal to or greater than the length of . /// -or- /// The number of elements in the source is greater than the available space from to the end of the destination . /// The type of the source cannot be cast automatically to the type of the destination . /// 2 public void CopyTo(Array array, int index) { throw NewNotImplementedException(); } public int Count { get { var copy = 0; foreach (var e in this) { copy++; } return copy; } } /// /// Gets an object that can be used to synchronize access to the . /// /// /// An object that can be used to synchronize access to the . /// /// 2 public object SyncRoot { get { return this; } } /// /// Gets a value indicating whether access to the is synchronized (thread safe). /// /// /// true if access to the is synchronized (thread safe); otherwise, false. /// /// 2 public bool IsSynchronized { get { throw NewNotImplementedException(); } } public bool IsReadOnly { get { return _retractPred == null; } } public bool Remove(T item) { if (_retractPred == null) throw new NotSupportedException("remove " + this); bool found = false; InForiegnFrame(() => { found = PlCall(_module, _retractPred, new PlTermV(KeyToTerm(item))); }); return found; } #endregion public List Copy() { var copy = new List(); foreach (var e in this) { copy.Add(e); } return copy; } public override string ToDebugString() { string ds = "" + Count; foreach (var kv in this) { ds += "," + kv; } return ds; } #region IEnumerable Members public IEnumerator GetEnumerator() { PrologCLR.RegisterCurrentThread(); return new PrologBackedCollectionEnumerator(this); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return new PrologBackedCollectionEnumerator(this); } public class PrologBackedCollectionEnumerator : IEnumerator { private readonly PrologBackedCollection _dictionary; private uint fframe = 0; private PlTermV termV; private PlQuery plQuery; private bool nonLeft = true; private object currentValue; public PrologBackedCollectionEnumerator(PrologBackedCollection dictionary) { _dictionary = dictionary; Reset(); } #region Implementation of IDisposable /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// 2 public void Dispose() { if (plQuery != null) { plQuery.Dispose(); plQuery = null; } nonLeft = true; currentValue = null; if (fframe != 0) libpl.PL_close_foreign_frame(fframe); fframe = 0; } #endregion #region Implementation of IEnumerator /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// /// The collection was modified after the enumerator was created. /// 2 public bool MoveNext() { if(!plQuery.NextSolution()) { Dispose(); return false; } nonLeft = false; PlTerm plQueryArgs = plQuery.Args[0]; currentValue = PrologCLR.CastTerm(plQueryArgs, _dictionary.keyType); ; return true; } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// /// The collection was modified after the enumerator was created. /// 2 public void Reset() { Dispose(); fframe = libpl.PL_open_foreign_frame(); termV = new PlTermV(1); plQuery = new PlQuery(_dictionary._module, _dictionary._querypred, termV); nonLeft = false; } /// /// Gets the element in the collection at the current position of the enumerator. /// /// /// The element in the collection at the current position of the enumerator. /// public T Current { get { if (nonLeft) { throw new Exception("no current element"); } return (T) currentValue; } } /// /// Gets the current element in the collection. /// /// /// The current element in the collection. /// /// The enumerator is positioned before the first element of the collection or after the last element. /// 2 object IEnumerator.Current { get { return Current; } } #endregion } #endregion } }