aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs107
1 files changed, 100 insertions, 7 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs
index 1be73f7..2bf9db7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs
@@ -39,6 +39,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
39 /// </summary> 39 /// </summary>
40 public class IndexedAnswers : YP.IClause 40 public class IndexedAnswers : YP.IClause
41 { 41 {
42 private int _arity;
42 // addAnswer adds the answer here and indexes it later. 43 // addAnswer adds the answer here and indexes it later.
43 private List<object[]> _allAnswers = new List<object[]>(); 44 private List<object[]> _allAnswers = new List<object[]>();
44 // The key has the arity of answers with non-null values for each indexed arg. The value 45 // The key has the arity of answers with non-null values for each indexed arg. The value
@@ -49,17 +50,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
49 private Dictionary<int, object> _gotAnswersForSignature = new Dictionary<int, object>(); 50 private Dictionary<int, object> _gotAnswersForSignature = new Dictionary<int, object>();
50 private const int MAX_INDEX_ARGS = 31; 51 private const int MAX_INDEX_ARGS = 31;
51 52
52 public IndexedAnswers() 53 public IndexedAnswers(int arity)
53 { 54 {
55 _arity = arity;
54 } 56 }
55 57
56 /// <summary> 58 /// <summary>
59 /// Append the answer to the list and update the indexes, if any.
57 /// Elements of answer must be ground, since arguments with unbound variables make this 60 /// Elements of answer must be ground, since arguments with unbound variables make this
58 /// into a dynamic rule which we don't index. 61 /// into a dynamic rule which we don't index.
59 /// </summary> 62 /// </summary>
60 /// <param name="answer"></param> 63 /// <param name="answer"></param>
61 public void addAnswer(object[] answer) 64 public void addAnswer(object[] answer)
62 { 65 {
66 addOrPrependAnswer(answer, false);
67 }
68
69 /// <summary>
70 /// Prepend the answer to the list and clear the indexes so that they must be re-computed
71 /// on the next call to match. (Only addAnswer will maintain the indexes while adding answers.)
72 /// Elements of answer must be ground, since arguments with unbound variables make this
73 /// into a dynamic rule which we don't index.
74 /// </summary>
75 /// <param name="answer"></param>
76 public void prependAnswer(object[] answer)
77 {
78 addOrPrependAnswer(answer, true);
79 }
80
81 /// <summary>
82 /// Do the work of addAnswer or prependAnswer.
83 /// </summary>
84 /// <param name="answer"></param>
85 private void addOrPrependAnswer(object[] answer, bool prepend)
86 {
87 if (answer.Length != _arity)
88 return;
89
63 // Store a copy of the answer array. 90 // Store a copy of the answer array.
64 object[] answerCopy = new object[answer.Length]; 91 object[] answerCopy = new object[answer.Length];
65 Variable.CopyStore copyStore = new Variable.CopyStore(); 92 Variable.CopyStore copyStore = new Variable.CopyStore();
@@ -69,12 +96,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
69 throw new InvalidOperationException 96 throw new InvalidOperationException
70 ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() + 97 ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() +
71 " unbound variables"); 98 " unbound variables");
72 _allAnswers.Add(answerCopy);
73 99
74 // If match has already indexed answers for a signature, we need to add 100 if (prepend)
75 // this to the existing indexed answers. 101 {
76 foreach (int signature in _gotAnswersForSignature.Keys) 102 _allAnswers.Insert(0, answerCopy);
77 indexAnswerForSignature(answerCopy, signature); 103 clearIndexes();
104 }
105 else
106 {
107 _allAnswers.Add(answerCopy);
108 // If match has already indexed answers for a signature, we need to add
109 // this to the existing indexed answers.
110 foreach (int signature in _gotAnswersForSignature.Keys)
111 indexAnswerForSignature(answerCopy, signature);
112 }
78 } 113 }
79 114
80 private void indexAnswerForSignature(object[] answer, int signature) 115 private void indexAnswerForSignature(object[] answer, int signature)
@@ -119,6 +154,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
119 154
120 public IEnumerable<bool> match(object[] arguments) 155 public IEnumerable<bool> match(object[] arguments)
121 { 156 {
157 if (arguments.Length != _arity)
158 yield break;
159
122 // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for 160 // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for
123 // each non-null index arg. 161 // each non-null index arg.
124 HashedList indexArgs = new HashedList(arguments.Length); 162 HashedList indexArgs = new HashedList(arguments.Length);
@@ -166,6 +204,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
166 204
167 // Find matches in answers. 205 // Find matches in answers.
168 IEnumerator<bool>[] iterators = new IEnumerator<bool>[arguments.Length]; 206 IEnumerator<bool>[] iterators = new IEnumerator<bool>[arguments.Length];
207 // Debug: If the caller asserts another answer into this same predicate during yield, the iterator
208 // over clauses will be corrupted. Should we take the time to copy answers?
169 foreach (object[] answer in answers) 209 foreach (object[] answer in answers)
170 { 210 {
171 bool gotMatch = true; 211 bool gotMatch = true;
@@ -201,6 +241,59 @@ namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog
201 } 241 }
202 } 242 }
203 243
244 public IEnumerable<bool> clause(object Head, object Body)
245 {
246 Head = YP.getValue(Head);
247 if (Head is Variable)
248 throw new PrologException("instantiation_error", "Head is an unbound variable");
249 object[] arguments = YP.getFunctorArgs(Head);
250
251 // We always match Head from _allAnswers, and the Body is Atom.a("true").
252 foreach (bool l1 in YP.unify(Body, Atom.a("true")))
253 {
254 // The caller can assert another answer into this same predicate during yield, so we have to
255 // make a copy of the answers.
256 foreach (object[] answer in _allAnswers.ToArray())
257 {
258 foreach (bool l2 in YP.unifyArrays(arguments, answer))
259 yield return false;
260 }
261 }
262 }
263
264 public IEnumerable<bool> retract(object Head, object Body)
265 {
266 Head = YP.getValue(Head);
267 if (Head is Variable)
268 throw new PrologException("instantiation_error", "Head is an unbound variable");
269 object[] arguments = YP.getFunctorArgs(Head);
270
271 // We always match Head from _allAnswers, and the Body is Atom.a("true").
272 foreach (bool l1 in YP.unify(Body, Atom.a("true")))
273 {
274 // The caller can assert another answer into this same predicate during yield, so we have to
275 // make a copy of the answers.
276 foreach (object[] answer in _allAnswers.ToArray())
277 {
278 foreach (bool l2 in YP.unifyArrays(arguments, answer))
279 {
280 _allAnswers.Remove(answer);
281 clearIndexes();
282 yield return false;
283 }
284 }
285 }
286 }
287
288 /// <summary>
289 /// After retracting or prepending an answer in _allAnswers, the indexes are invalid, so clear them.
290 /// </summary>
291 private void clearIndexes()
292 {
293 _indexedAnswers.Clear();
294 _gotAnswersForSignature.Clear();
295 }
296
204 /// <summary> 297 /// <summary>
205 /// A HashedList extends an ArrayList with methods to get a hash and to check equality 298 /// A HashedList extends an ArrayList with methods to get a hash and to check equality
206 /// based on the elements of the list. 299 /// based on the elements of the list.