diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs | 576 |
1 files changed, 288 insertions, 288 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs index 3eac5fa..05b0a01 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/YieldProlog/IndexedAnswers.cs | |||
@@ -1,288 +1,288 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007-2008, Jeff Thompson | 2 | * Copyright (C) 2007-2008, Jeff Thompson |
3 | * | 3 | * |
4 | * All rights reserved. | 4 | * All rights reserved. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
8 | * | 8 | * |
9 | * * Redistributions of source code must retain the above copyright | 9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above copyright | 11 | * * Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | 13 | * documentation and/or other materials provided with the distribution. |
14 | * * Neither the name of the copyright holder nor the names of its contributors | 14 | * * Neither the name of the copyright holder nor the names of its contributors |
15 | * may be used to endorse or promote products derived from this software | 15 | * may be used to endorse or promote products derived from this software |
16 | * without specific prior written permission. | 16 | * without specific prior written permission. |
17 | * | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | using System; | 31 | using System; |
32 | using System.Collections; | 32 | using System.Collections; |
33 | using System.Collections.Generic; | 33 | using System.Collections.Generic; |
34 | 34 | ||
35 | namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog | 35 | namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.YieldProlog |
36 | { | 36 | { |
37 | /// <summary> | 37 | /// <summary> |
38 | /// An IndexedAnswers holds answers to a query based on the values of index arguments. | 38 | /// An IndexedAnswers holds answers to a query based on the values of index arguments. |
39 | /// </summary> | 39 | /// </summary> |
40 | public class IndexedAnswers : YP.IClause | 40 | public class IndexedAnswers : YP.IClause |
41 | { | 41 | { |
42 | // addAnswer adds the answer here and indexes it later. | 42 | // addAnswer adds the answer here and indexes it later. |
43 | private List<object[]> _allAnswers = new List<object[]>(); | 43 | 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 | 44 | // The key has the arity of answers with non-null values for each indexed arg. The value |
45 | // is a list of the matching answers. The signature is implicit in the pattern on non-null index args. | 45 | // is a list of the matching answers. The signature is implicit in the pattern on non-null index args. |
46 | private Dictionary<HashedList, List<object[]>> _indexedAnswers = | 46 | private Dictionary<HashedList, List<object[]>> _indexedAnswers = |
47 | new Dictionary<HashedList, List<object[]>>(); | 47 | new Dictionary<HashedList, List<object[]>>(); |
48 | // Keeps track of whether we have started adding entries to _indexedAnswers for the signature. | 48 | // Keeps track of whether we have started adding entries to _indexedAnswers for the signature. |
49 | private Dictionary<int, object> _gotAnswersForSignature = new Dictionary<int, object>(); | 49 | private Dictionary<int, object> _gotAnswersForSignature = new Dictionary<int, object>(); |
50 | private const int MAX_INDEX_ARGS = 31; | 50 | private const int MAX_INDEX_ARGS = 31; |
51 | 51 | ||
52 | public IndexedAnswers() | 52 | public IndexedAnswers() |
53 | { | 53 | { |
54 | } | 54 | } |
55 | 55 | ||
56 | /// <summary> | 56 | /// <summary> |
57 | /// Elements of answer must be ground, since arguments with unbound variables make this | 57 | /// Elements of answer must be ground, since arguments with unbound variables make this |
58 | /// into a dynamic rule which we don't index. | 58 | /// into a dynamic rule which we don't index. |
59 | /// </summary> | 59 | /// </summary> |
60 | /// <param name="answer"></param> | 60 | /// <param name="answer"></param> |
61 | public void addAnswer(object[] answer) | 61 | public void addAnswer(object[] answer) |
62 | { | 62 | { |
63 | // Store a copy of the answer array. | 63 | // Store a copy of the answer array. |
64 | object[] answerCopy = new object[answer.Length]; | 64 | object[] answerCopy = new object[answer.Length]; |
65 | Variable.CopyStore copyStore = new Variable.CopyStore(); | 65 | Variable.CopyStore copyStore = new Variable.CopyStore(); |
66 | for (int i = 0; i < answer.Length; ++i) | 66 | for (int i = 0; i < answer.Length; ++i) |
67 | answerCopy[i] = YP.makeCopy(answer[i], copyStore); | 67 | answerCopy[i] = YP.makeCopy(answer[i], copyStore); |
68 | if (copyStore.getNUniqueVariables() > 0) | 68 | if (copyStore.getNUniqueVariables() > 0) |
69 | throw new InvalidOperationException | 69 | throw new InvalidOperationException |
70 | ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() + | 70 | ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() + |
71 | " unbound variables"); | 71 | " unbound variables"); |
72 | _allAnswers.Add(answerCopy); | 72 | _allAnswers.Add(answerCopy); |
73 | 73 | ||
74 | // If match has already indexed answers for a signature, we need to add | 74 | // If match has already indexed answers for a signature, we need to add |
75 | // this to the existing indexed answers. | 75 | // this to the existing indexed answers. |
76 | foreach(int signature in _gotAnswersForSignature.Keys) | 76 | foreach(int signature in _gotAnswersForSignature.Keys) |
77 | indexAnswerForSignature(answerCopy, signature); | 77 | indexAnswerForSignature(answerCopy, signature); |
78 | } | 78 | } |
79 | 79 | ||
80 | private void indexAnswerForSignature(object[] answer, int signature) | 80 | private void indexAnswerForSignature(object[] answer, int signature) |
81 | { | 81 | { |
82 | // First find out which of the answer values can be used as an index. | 82 | // First find out which of the answer values can be used as an index. |
83 | object[] indexValues = new object[answer.Length]; | 83 | object[] indexValues = new object[answer.Length]; |
84 | for (int i = 0; i < answer.Length; ++i) | 84 | for (int i = 0; i < answer.Length; ++i) |
85 | { | 85 | { |
86 | // We limit the number of indexed args in a 32-bit signature. | 86 | // We limit the number of indexed args in a 32-bit signature. |
87 | if (i >= MAX_INDEX_ARGS) | 87 | if (i >= MAX_INDEX_ARGS) |
88 | indexValues[i] = null; | 88 | indexValues[i] = null; |
89 | else | 89 | else |
90 | indexValues[i] = getIndexValue(YP.getValue(answer[i])); | 90 | indexValues[i] = getIndexValue(YP.getValue(answer[i])); |
91 | } | 91 | } |
92 | 92 | ||
93 | // We need an entry in indexArgs from indexValues for each 1 bit in signature. | 93 | // We need an entry in indexArgs from indexValues for each 1 bit in signature. |
94 | HashedList indexArgs = new HashedList(indexValues.Length); | 94 | HashedList indexArgs = new HashedList(indexValues.Length); |
95 | for (int i = 0; i < indexValues.Length; ++i) | 95 | for (int i = 0; i < indexValues.Length; ++i) |
96 | { | 96 | { |
97 | if ((signature & (1 << i)) == 0) | 97 | if ((signature & (1 << i)) == 0) |
98 | indexArgs.Add(null); | 98 | indexArgs.Add(null); |
99 | else | 99 | else |
100 | { | 100 | { |
101 | if (indexValues[i] == null) | 101 | if (indexValues[i] == null) |
102 | // The signature wants an index value here, but we don't have one so | 102 | // The signature wants an index value here, but we don't have one so |
103 | // we can't add it as an answer for this signature. | 103 | // we can't add it as an answer for this signature. |
104 | return; | 104 | return; |
105 | else | 105 | else |
106 | indexArgs.Add(indexValues[i]); | 106 | indexArgs.Add(indexValues[i]); |
107 | } | 107 | } |
108 | } | 108 | } |
109 | 109 | ||
110 | // Add the answer to the answers list for indexArgs, creating the entry if needed. | 110 | // Add the answer to the answers list for indexArgs, creating the entry if needed. |
111 | List<object[]> answers; | 111 | List<object[]> answers; |
112 | if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) | 112 | if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) |
113 | { | 113 | { |
114 | answers = new List<object[]>(); | 114 | answers = new List<object[]>(); |
115 | _indexedAnswers[indexArgs] = answers; | 115 | _indexedAnswers[indexArgs] = answers; |
116 | } | 116 | } |
117 | answers.Add(answer); | 117 | answers.Add(answer); |
118 | } | 118 | } |
119 | 119 | ||
120 | public IEnumerable<bool> match(object[] arguments) | 120 | public IEnumerable<bool> match(object[] arguments) |
121 | { | 121 | { |
122 | // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for | 122 | // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for |
123 | // each non-null index arg. | 123 | // each non-null index arg. |
124 | HashedList indexArgs = new HashedList(arguments.Length); | 124 | HashedList indexArgs = new HashedList(arguments.Length); |
125 | bool gotAllIndexArgs = true; | 125 | bool gotAllIndexArgs = true; |
126 | int signature = 0; | 126 | int signature = 0; |
127 | for (int i = 0; i < arguments.Length; ++i) | 127 | for (int i = 0; i < arguments.Length; ++i) |
128 | { | 128 | { |
129 | object indexValue = null; | 129 | object indexValue = null; |
130 | if (i < MAX_INDEX_ARGS) | 130 | if (i < MAX_INDEX_ARGS) |
131 | { | 131 | { |
132 | // We limit the number of args in a 32-bit signature. | 132 | // We limit the number of args in a 32-bit signature. |
133 | indexValue = getIndexValue(YP.getValue(arguments[i])); | 133 | indexValue = getIndexValue(YP.getValue(arguments[i])); |
134 | if (indexValue != null) | 134 | if (indexValue != null) |
135 | signature += (1 << i); | 135 | signature += (1 << i); |
136 | } | 136 | } |
137 | if (indexValue == null) | 137 | if (indexValue == null) |
138 | gotAllIndexArgs = false; | 138 | gotAllIndexArgs = false; |
139 | indexArgs.Add(indexValue); | 139 | indexArgs.Add(indexValue); |
140 | } | 140 | } |
141 | 141 | ||
142 | List<object[]> answers; | 142 | List<object[]> answers; |
143 | if (signature == 0) | 143 | if (signature == 0) |
144 | // No index args, so we have to match from _allAnswers. | 144 | // No index args, so we have to match from _allAnswers. |
145 | answers = _allAnswers; | 145 | answers = _allAnswers; |
146 | else | 146 | else |
147 | { | 147 | { |
148 | if (!_gotAnswersForSignature.ContainsKey(signature)) | 148 | if (!_gotAnswersForSignature.ContainsKey(signature)) |
149 | { | 149 | { |
150 | // We need to create the entry in _indexedAnswers. | 150 | // We need to create the entry in _indexedAnswers. |
151 | foreach (object[] answer in _allAnswers) | 151 | foreach (object[] answer in _allAnswers) |
152 | indexAnswerForSignature(answer, signature); | 152 | indexAnswerForSignature(answer, signature); |
153 | // Mark that we did this signature. | 153 | // Mark that we did this signature. |
154 | _gotAnswersForSignature[signature] = null; | 154 | _gotAnswersForSignature[signature] = null; |
155 | } | 155 | } |
156 | if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) | 156 | if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) |
157 | yield break; | 157 | yield break; |
158 | } | 158 | } |
159 | 159 | ||
160 | if (gotAllIndexArgs) | 160 | if (gotAllIndexArgs) |
161 | { | 161 | { |
162 | // All the arguments were already bound, so we don't need to do bindings. | 162 | // All the arguments were already bound, so we don't need to do bindings. |
163 | yield return false; | 163 | yield return false; |
164 | yield break; | 164 | yield break; |
165 | } | 165 | } |
166 | 166 | ||
167 | // Find matches in answers. | 167 | // Find matches in answers. |
168 | IEnumerator<bool>[] iterators = new IEnumerator<bool>[arguments.Length]; | 168 | IEnumerator<bool>[] iterators = new IEnumerator<bool>[arguments.Length]; |
169 | foreach (object[] answer in answers) | 169 | foreach (object[] answer in answers) |
170 | { | 170 | { |
171 | bool gotMatch = true; | 171 | bool gotMatch = true; |
172 | int nIterators = 0; | 172 | int nIterators = 0; |
173 | // Try to bind all the arguments. | 173 | // Try to bind all the arguments. |
174 | for (int i = 0; i < arguments.Length; ++i) | 174 | for (int i = 0; i < arguments.Length; ++i) |
175 | { | 175 | { |
176 | if (indexArgs[i] != null) | 176 | if (indexArgs[i] != null) |
177 | // We already matched this argument by looking up _indexedAnswers. | 177 | // We already matched this argument by looking up _indexedAnswers. |
178 | continue; | 178 | continue; |
179 | 179 | ||
180 | IEnumerator<bool> iterator = YP.unify(arguments[i], answer[i]).GetEnumerator(); | 180 | IEnumerator<bool> iterator = YP.unify(arguments[i], answer[i]).GetEnumerator(); |
181 | iterators[nIterators++] = iterator; | 181 | iterators[nIterators++] = iterator; |
182 | // MoveNext() is true if YP.unify succeeds. | 182 | // MoveNext() is true if YP.unify succeeds. |
183 | if (!iterator.MoveNext()) | 183 | if (!iterator.MoveNext()) |
184 | { | 184 | { |
185 | gotMatch = false; | 185 | gotMatch = false; |
186 | break; | 186 | break; |
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | try | 190 | try |
191 | { | 191 | { |
192 | if (gotMatch) | 192 | if (gotMatch) |
193 | yield return false; | 193 | yield return false; |
194 | } | 194 | } |
195 | finally | 195 | finally |
196 | { | 196 | { |
197 | // Manually finalize all the iterators. | 197 | // Manually finalize all the iterators. |
198 | for (int i = 0; i < nIterators; ++i) | 198 | for (int i = 0; i < nIterators; ++i) |
199 | iterators[i].Dispose(); | 199 | iterators[i].Dispose(); |
200 | } | 200 | } |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | /// <summary> | 204 | /// <summary> |
205 | /// A HashedList extends an ArrayList with methods to get a hash and to check equality | 205 | /// A HashedList extends an ArrayList with methods to get a hash and to check equality |
206 | /// based on the elements of the list. | 206 | /// based on the elements of the list. |
207 | /// </summary> | 207 | /// </summary> |
208 | public class HashedList : ArrayList | 208 | public class HashedList : ArrayList |
209 | { | 209 | { |
210 | private bool _gotHashCode = false; | 210 | private bool _gotHashCode = false; |
211 | private int _hashCode; | 211 | private int _hashCode; |
212 | 212 | ||
213 | public HashedList() | 213 | public HashedList() |
214 | : base() | 214 | : base() |
215 | { | 215 | { |
216 | } | 216 | } |
217 | 217 | ||
218 | public HashedList(int capacity) | 218 | public HashedList(int capacity) |
219 | : base(capacity) | 219 | : base(capacity) |
220 | { | 220 | { |
221 | } | 221 | } |
222 | 222 | ||
223 | public HashedList(ICollection c) | 223 | public HashedList(ICollection c) |
224 | : base(c) | 224 | : base(c) |
225 | { | 225 | { |
226 | } | 226 | } |
227 | 227 | ||
228 | // Debug: Should override all the other methods that change this. | 228 | // Debug: Should override all the other methods that change this. |
229 | public override int Add(object value) | 229 | public override int Add(object value) |
230 | { | 230 | { |
231 | _gotHashCode = false; | 231 | _gotHashCode = false; |
232 | return base.Add(value); | 232 | return base.Add(value); |
233 | } | 233 | } |
234 | 234 | ||
235 | public override int GetHashCode() | 235 | public override int GetHashCode() |
236 | { | 236 | { |
237 | if (!_gotHashCode) | 237 | if (!_gotHashCode) |
238 | { | 238 | { |
239 | int hashCode = 1; | 239 | int hashCode = 1; |
240 | foreach (object obj in this) | 240 | foreach (object obj in this) |
241 | hashCode = 31 * hashCode + (obj == null ? 0 : obj.GetHashCode()); | 241 | hashCode = 31 * hashCode + (obj == null ? 0 : obj.GetHashCode()); |
242 | _hashCode = hashCode; | 242 | _hashCode = hashCode; |
243 | _gotHashCode = true; | 243 | _gotHashCode = true; |
244 | } | 244 | } |
245 | return _hashCode; | 245 | return _hashCode; |
246 | } | 246 | } |
247 | 247 | ||
248 | public override bool Equals(object obj) | 248 | public override bool Equals(object obj) |
249 | { | 249 | { |
250 | if (!(obj is ArrayList)) | 250 | if (!(obj is ArrayList)) |
251 | return false; | 251 | return false; |
252 | 252 | ||
253 | ArrayList objList = (ArrayList)obj; | 253 | ArrayList objList = (ArrayList)obj; |
254 | if (objList.Count != Count) | 254 | if (objList.Count != Count) |
255 | return false; | 255 | return false; |
256 | 256 | ||
257 | for (int i = 0; i < Count; ++i) | 257 | for (int i = 0; i < Count; ++i) |
258 | { | 258 | { |
259 | object value = objList[i]; | 259 | object value = objList[i]; |
260 | if (value == null) | 260 | if (value == null) |
261 | { | 261 | { |
262 | if (this[i] != null) | 262 | if (this[i] != null) |
263 | return false; | 263 | return false; |
264 | } | 264 | } |
265 | else | 265 | else |
266 | { | 266 | { |
267 | if (!value.Equals(this[i])) | 267 | if (!value.Equals(this[i])) |
268 | return false; | 268 | return false; |
269 | } | 269 | } |
270 | } | 270 | } |
271 | return true; | 271 | return true; |
272 | } | 272 | } |
273 | } | 273 | } |
274 | 274 | ||
275 | /// <summary> | 275 | /// <summary> |
276 | /// If we keep an index on value, return the value, or null if we don't index it. | 276 | /// If we keep an index on value, return the value, or null if we don't index it. |
277 | /// </summary> | 277 | /// </summary> |
278 | /// <param name="value">the term to examine. Assume you already called YP.getValue(value)</param> | 278 | /// <param name="value">the term to examine. Assume you already called YP.getValue(value)</param> |
279 | /// <returns></returns> | 279 | /// <returns></returns> |
280 | public static object getIndexValue(object value) | 280 | public static object getIndexValue(object value) |
281 | { | 281 | { |
282 | if (value is Atom || value is string || value is Int32 || value is DateTime) | 282 | if (value is Atom || value is string || value is Int32 || value is DateTime) |
283 | return value; | 283 | return value; |
284 | else | 284 | else |
285 | return null; | 285 | return null; |
286 | } | 286 | } |
287 | } | 287 | } |
288 | } | 288 | } |