Titan Core Initial Contribution
[deliverable/titan.core.git] / core / Struct_of.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "Struct_of.hh"
9
10 #include "../common/memory.h"
11 #include "Error.hh"
12 #include "Logger.hh"
13 #include "Template.hh"
14
15 #include "../common/dbgnew.hh"
16 #include <string.h>
17
18 void **allocate_pointers(int n_elements)
19 {
20 void **ret_val = (void**)Malloc(n_elements * sizeof(void*));
21 for (int elem_count = 0; elem_count < n_elements; elem_count++)
22 ret_val[elem_count] = NULL;
23 return ret_val;
24 }
25
26 void **reallocate_pointers(void **old_pointer, int old_n_elements,
27 int n_elements)
28 {
29 void **ret_val = (void**)Realloc(old_pointer, n_elements * sizeof(void*));
30 for (int elem_count = old_n_elements; elem_count < n_elements; elem_count++)
31 ret_val[elem_count] = NULL;
32 return ret_val;
33 }
34
35 void free_pointers(void **old_pointer)
36 {
37 Free(old_pointer);
38 }
39
40 /*
41 Generic comparison function for 'set of' values. The fifth argument
42 is a pointer to a type-specific callback function: boolean
43 compare_function(Base_Type *left_ptr, int left_index,
44 Base_Type *right_ptr, int right_index);
45
46 - Arguments left_ptr and right_ptr shall point to the operands of comparison.
47 They are handled transparently by the comparison function.
48
49 - The function returns whether the element of left operand at position
50 left_index equals to the element of right operand at position right_index.
51
52 - In case of invalid value pointers, index overflow or negative indices the
53 behaviour of the function is undefined.
54 */
55 #ifdef TITAN_RUNTIME_2
56 boolean compare_set_of(const Record_Of_Type *left_ptr, int left_size,
57 const Record_Of_Type *right_ptr, int right_size,
58 compare_function_t compare_function)
59 #else
60 boolean compare_set_of(const Base_Type *left_ptr, int left_size,
61 const Base_Type *right_ptr, int right_size,
62 compare_function_t compare_function)
63 #endif
64 {
65 if (left_size < 0 || right_size < 0 ||
66 left_ptr == NULL || right_ptr == NULL)
67 {
68 TTCN_error("Internal error: compare_set_of: invalid argument.");
69 }
70
71 // if the sizes are different the values cannot be equal
72 if (left_size != right_size) return FALSE;
73 // if both values are empty they must be equal
74 if (left_size == 0) return TRUE;
75
76 //stores which have already been matched
77 boolean *covered = (boolean*)Malloc(left_size * sizeof(boolean));
78 //initially none of them
79 memset(covered, 0, left_size * sizeof(boolean));
80
81 boolean pair_found;
82 int left_index, right_index;//the actual indices
83 int first_on_right = 0;//index of the first element to check on the right side
84 //index of the last element to check on the right side
85 int last_on_right = left_size-1;
86
87 for(left_index = 0; left_index < left_size; left_index++)
88 {
89 pair_found = FALSE;
90 for(right_index=first_on_right;right_index<=last_on_right;right_index++)
91 {
92 if(!covered[right_index]
93 && compare_function(left_ptr, left_index, right_ptr, right_index))
94 {
95 //a new match was found
96 covered[right_index] = TRUE;
97 //if it is the first then check if we can increase the index more,
98 // reducing the elements that need to be checked
99 if(right_index == first_on_right)
100 while(++first_on_right<last_on_right && covered[first_on_right]){}
101 //if it is the last then check if we can decrease the index more,
102 // reducing the elements that need to be checked
103 if(right_index == last_on_right)
104 while(--last_on_right>first_on_right && covered[last_on_right]){}
105 pair_found = TRUE;
106 break;
107 }
108 }
109 //if we can't find a pair to any of the elements, the sets can not
110 // match any longer
111 if(!pair_found){
112 Free(covered);
113 return FALSE;
114 }
115 }
116
117 //if we found a pair to all the elements then they are the same
118 Free(covered);
119 return TRUE;
120 }
121
122 /*
123 Simplified matching function for 'record of' types. It is used when the
124 template does not contain permutation matching constructs.
125 The fifth argument is a pointer to a type-specific callback function:
126 boolean match_function(const Base_Type *value_ptr, int value_index,
127 const Restricted_Length_Template *template_ptr, int template_index);
128
129 - Arguments value_ptr and template_ptr shall point to the corresponding
130 value and template object. They are handled transparently by the matching
131 function.
132
133 - If both index arguments are non-negative the function returns whether
134 the value at position value_index matches the template_index-th
135 element in the template.
136
137 - If value_index is negative the function returns whether the
138 element in the template at index template_index is a '*'
139 (ANY_OR_NONE) wildcard.
140
141 - Otherwise (in case of invalid pointers, index overflow or negative
142 template_index) the behaviour of the function is undefined.
143
144 The very same abstract algorithm is used in the matching of types of
145 bitstring, octetstring, hexstring. The only differences are how we
146 match 2 elements, how we find out if a template element is
147 an ANY_OR_NONE / ANY element
148 */
149
150 boolean match_array(const Base_Type *value_ptr, int value_size,
151 const Restricted_Length_Template *template_ptr, int template_size,
152 match_function_t match_function)
153 {
154 if (value_ptr == NULL || value_size < 0 || template_ptr == NULL ||
155 template_size < 0)
156 TTCN_error("Internal error: match_array: invalid argument.");
157
158 // the empty template matches the empty value only
159 if (template_size == 0) return value_size == 0;
160
161 int template_index = 0;//the index of the template we are examining
162
163 if (value_size == 0){
164 //We matched if the remaining templates are
165 // asterisks
166 while(template_index < template_size &&
167 match_function(value_ptr, -1, template_ptr, template_index))
168 template_index++;
169
170 return template_index == template_size;
171 }
172
173 int value_index = 0;//the index of the value we are examining at the point
174 //the index of the last asterisk found in the template at the moment
175 // -1 if no asterisks were found yet
176 int last_asterisk = -1;
177 //this is the index of the last value that is matched by
178 // the last asterisk in the template
179 int last_value_to_asterisk = -1;
180
181 //must finish as we always increase one of the 4 indices or we return
182 // and there are limited number of templates and values
183 for(;;)
184 {
185 if(match_function(value_ptr, -1, template_ptr, template_index))
186 {
187 //if we found an asterisk we administer it, and step in the template
188 last_asterisk = template_index++;
189 last_value_to_asterisk = value_index;
190 }else if(match_function(value_ptr,value_index,template_ptr,template_index))
191 {
192 //if we found a matching pair we step in both
193 value_index++;
194 template_index++;
195 } else {
196 //if we didn't match and we found no asterisk the match failed
197 if(last_asterisk == -1) return FALSE;
198 //if we found an asterisk than fall back to it
199 //and step the value index
200 template_index = last_asterisk +1;
201 value_index = ++last_value_to_asterisk;
202 }
203
204 if(value_index == value_size && template_index == template_size)
205 {
206 //we finished clean
207 return TRUE;
208 } else if(template_index == template_size)
209 {
210 //value_index != value_size at this point so it is pointless
211 // to check it in the if statement
212 //At the end of the template
213 if(match_function(value_ptr, -1, template_ptr, template_index-1)) {
214 //if the templates last element is an asterisk it eats up the values
215 return TRUE;
216 } else if (last_asterisk == -1){
217 //if there were no asterisk the match failed
218 return FALSE;
219 } else{
220 //fall back to the asterisk, and step the value's indices
221 template_index = last_asterisk+1;
222 value_index = ++last_value_to_asterisk;
223 }
224 } else if(value_index == value_size)
225 {
226 //template_index != template_size at this point so it is pointless
227 // to check it in the if statement
228 //At the end of the value we matched if the remaining templates are
229 // asterisks
230 while(template_index < template_size &&
231 match_function(value_ptr, -1, template_ptr, template_index))
232 template_index++;
233
234 return template_index == template_size;
235 }
236 }
237 }
238
239 /* Ancillary classes for 'set of' matching */
240
241 namespace {
242
243 enum edge_status { UNKNOWN, NO_EDGE, EDGE, PAIRS };
244
245 /* Class Matching_Table:
246 * Responsibilities
247 * - index transformation to skip asterisks in the template
248 * the table is initialized in constructor
249 * - maintain a matrix that stores the status of edges
250 * (template <-> value relations)
251 * table is initialized explicitly
252 * - a flag for each value element to indicate whether it is covered
253 * Note: All dynamically allocated memory is collected into this class
254 * to avoid memory leaks in case of errors (exceptions).
255 */
256
257 class Matching_Table {
258 match_function_t match_function;
259 int value_size;
260 int value_start;
261 int template_size;
262 int template_start;
263 int n_asterisks;
264 int *template_index_table;
265 edge_status **edge_matrix;
266 boolean *covered_vector; //tells if a value is covered
267
268 //if the value is covered, then tells by whom it is covered
269 int *covered_index_vector;
270 int nof_covered;
271 int *paired_templates;
272
273 //the matching function requires these pointers
274 const Base_Type *value_ptr;
275
276 //they are allocated and freed outside
277 const Restricted_Length_Template *template_ptr;
278
279 public:
280 //the match_set_of will be called from the permutation matcher
281 // where the beginning of the examined set might not be at 0 position
282 Matching_Table(const Base_Type *par_value_ptr, int par_value_start,
283 int par_value_size,const Restricted_Length_Template *par_template_ptr,
284 int par_template_start, int par_template_size,
285 match_function_t par_match_function)
286 {
287 match_function = par_match_function;
288 value_size = par_value_size;
289 value_start = par_value_start;
290 template_start = par_template_start;
291 value_ptr = par_value_ptr;
292 template_ptr = par_template_ptr;
293 n_asterisks = 0;
294 nof_covered = 0;//to get rid of the linear summing
295
296 // we won't use all elements if there are asterisks in template
297 // it is cheaper to allocate it once instead of realloc'ing
298 template_index_table = new int[par_template_size];
299 // locating the asterisks in the template
300 for (int i = 0; i < par_template_size; i++)
301 {
302 if(match_function(value_ptr, -1,template_ptr, par_template_start+i))
303 n_asterisks++;
304 else template_index_table[i - n_asterisks] = i;
305 }
306 // don't count the asterisks
307 template_size = par_template_size - n_asterisks;
308
309 edge_matrix = NULL;
310 covered_vector = NULL;
311 covered_index_vector = NULL;
312 paired_templates = NULL;
313 }
314
315 ~Matching_Table()
316 {
317 delete [] template_index_table;
318 if (edge_matrix != NULL)
319 {
320 for (int i = 0; i < template_size; i++) delete [] edge_matrix[i];
321 delete [] edge_matrix;
322 }
323 delete [] covered_vector;
324 delete [] covered_index_vector;
325 delete [] paired_templates;
326 }
327
328 int get_template_size() const { return template_size; }
329
330 boolean has_asterisk() const { return n_asterisks > 0; }
331
332 void create_matrix()
333 {
334 edge_matrix = new edge_status*[template_size];
335 for (int i = 0; i < template_size; i++)
336 {
337 edge_matrix[i] = new edge_status[value_size];
338 for (int j = 0; j < value_size; j++) edge_matrix[i][j] = UNKNOWN;
339 }
340 covered_vector = new boolean[value_size];
341 for (int j = 0; j < value_size; j++) covered_vector[j] = FALSE;
342
343 paired_templates = new int[template_size];
344 for(int j = 0; j < template_size; j++) paired_templates[j] = -1;
345
346 covered_index_vector = new int[value_size];
347 }
348
349 edge_status get_edge(int template_index, int value_index)
350 {
351 if (edge_matrix[template_index][value_index] == UNKNOWN)
352 {
353 if (match_function(value_ptr, value_start + value_index,
354 template_ptr,
355 template_start + template_index_table[template_index]))
356 {
357 edge_matrix[template_index][value_index] = EDGE;
358 }else{
359 edge_matrix[template_index][value_index] = NO_EDGE;
360 }
361 }
362 return edge_matrix[template_index][value_index];
363 }
364
365 void set_edge(int template_index, int value_index, edge_status new_status)
366 {
367 edge_matrix[template_index][value_index] = new_status;
368 }
369
370 boolean is_covered(int value_index) const
371 {
372 return covered_vector[value_index];
373 }
374
375 int covered_by(int value_index) const
376 {
377 return covered_index_vector[value_index];
378 }
379
380 int get_nof_covered() const
381 {
382 return nof_covered;
383 }
384
385 void set_covered(int value_index, int template_index)
386 {
387 if(!covered_vector[value_index])
388 nof_covered++;
389
390 covered_vector[value_index] = TRUE;
391 covered_index_vector[value_index] = template_index;
392 }
393
394 boolean is_paired(int j)
395 {
396 return paired_templates[j] != -1;
397 }
398
399 void set_paired(int j, int i)
400 {
401 paired_templates[j] = i;
402 }
403
404 int get_paired(int j)
405 {
406 return paired_templates[j];
407 }
408 };
409
410 }
411
412 namespace {
413
414 /* Tree-list. It is used for storing a tree in BFS order. That is: the
415 * first element is the root of the tree, it is followed by its
416 * neighbours then the neighbours of the neighbours follow, and so
417 * on. The elements can be reached sequentially by the use of the next
418 * pointer. Also the parent of an element can be reached via a pointer
419 * also. Elements can be inserted in the tree, and with the help of
420 * the functions one can move or search in the tree.
421 */
422
423 class Tree_list {
424 /* Elements of the tree-list. */
425 struct List_elem {
426 int data;
427 List_elem *next, *parent;
428 } head, *current;
429
430 public:
431 Tree_list(int head_data)
432 {
433 head.data = head_data;
434 head.next = NULL;
435 head.parent = NULL;
436 current = &head;
437 }
438
439 ~Tree_list()
440 {
441 for (List_elem *ptr = head.next; ptr != NULL; )
442 {
443 List_elem *next = ptr->next;
444 delete ptr;
445 ptr = next;
446 }
447 }
448
449 void insert_data(int new_data)
450 {
451 List_elem* newptr = new List_elem;
452 newptr->data = new_data;
453 newptr->next = current->next;
454 newptr->parent = current;
455 current->next = newptr;
456 }
457
458 void back_step()
459 {
460 if (current->parent != NULL) current = current->parent;
461 }
462
463 void step_forward()
464 {
465 if (current->next != NULL) current = current->next;
466 }
467
468 int head_value() const { return head.data; }
469 int actual_data()const { return current->data; }
470 boolean is_head() const { return current->parent == NULL; }
471 boolean end_of_list() const { return current->next == NULL; }
472
473 boolean do_exists(int find_data) const
474 {
475 for (const List_elem *ptr = &head; ptr != NULL; ptr = ptr->next)
476 if (ptr->data == find_data) return TRUE;
477 return FALSE;
478 }
479 };
480
481 }
482
483 /* Generic matching function for 'set of' values. The interpretation
484 * of third argument is the same as for 'record of'.
485 */
486
487 /*
488 find_pairs implements an algorithm of matching sets using a graph
489 algorithm. The correctness of the algorithm is _not_ proven here just
490 the steps of the algorithm are described. Let denote the two sets by A
491 and B. The algorithm is for deciding whether for all elements of A
492 there can be found a matching pair in B. This means that the function
493 returns true when A matches a subset of B. If the two sets' sizes
494 equal then the function returns true if the two sets match each other.
495
496 The algorithm. For all elements in A the following:
497
498 Initialize some variables. After that start a cycle. In the cycle we
499 try to find a pair for the actual element (at the start actual element
500 is the element from set A - later it may change). The result can be:
501
502 case 1: If there is one pair the cycle is finished we administer the
503 pairs (it may need a recursive modification in the
504 other pairs) and after that the algorithm continues
505 with the next element in A.
506
507 case 2: If there is no pair the algorithm returns false because if
508 there is no pair for one element, that means that the
509 two sets cannot be equal/matching. case 3: If there
510 is a "pair" but is already assigned as a pair to an
511 other element of A then this "pair" element is put in
512 the alternating tree list (if it's not in the list
513 already). The alternating tree is built to modify and
514 administer existing pairs in a way that the elements
515 which already have pairs will have pairs (but maybe
516 other ones) and we will be able to assign a pair for
517 the actual element also.
518
519 If we haven't found a pair which is not assigned already nor we have
520 found only non-matching elements then (in other words in case 3) we
521 built an alternating tree with some "pairs" and continue the cycle by
522 going to the next element of the alternating tree list. If it is from
523 set A, we do as described above, if not - the actual element is from
524 set B - we do the following. As this element is a pair of another
525 element it should have a pair, so if its pair is not already in the
526 alternating tree, we add it to the alternating tree list and continue
527 the cycle with the next element of the list.
528
529 If the algorithm doesn't terminate within the cycles by finding no
530 pairs (case 2) then it will find pairs (simply or with the help of
531 alternating trees) for each element of set A, meaning the two sets are
532 matching. If it terminates that means that the matching process
533 already failed somewhere resulting in non-matching.
534 */
535
536 /*
537 match_set_of implements a set matching algorithm using graphs.
538
539 The algorithm implements subset, exact and superset matching.
540 The description will be general, to ease understanding, giving up on the
541 specific details. Later, when the base algorithm is already understood
542 I will mention a part that ain't really needed for this algorithm, but it
543 is still in the code.
544
545 The correctness of the algorithm is _not_ proven here just
546 the steps of the algorithm are described. Let denote the two sets by A
547 and B.
548 The algorithm returns true if the relationship between A and B is right
549 (A is subset of B and thats what we were checking for).
550
551 The algorithm:
552
553 In the beginning it makes some checks to see if we can quickly deny matching.
554
555 Than it goes through the elements of set A and tries to find a matching element
556 in set B which still has no pair. If it finds a matching element, then
557 it is administered.
558 If no new matching elements can be found than:
559 -if the matching requirements (subset) allows this, we step to the next
560 element of set A.
561 -if the requirements (exact/superset) don't allow this, then we insert
562 B's element in the tree, trying to find a new element of B
563 for his pair in A.
564
565 The tree is walked recursively searching a new pair for elements of set A
566 (the elements of set B are only inserted so we have links between A's elements,
567 when in case of success we try to administer the changes).
568
569 The algorithm can end on two ways:
570 -not even with the recursive search can we find a pair for an element
571 and the matching requirement doesn't allow this, so we return false.
572 -we went through all of A's elements, in this case we decide based
573 on the matching requirement and the number of pairs found
574 (for example in subset matching the number of A's elements and the
575 number of found pairs must be the same).
576
577 The strange piece of code is when we work with the pair_list.
578 It stores which element of set A is paired with an element of set B
579 (if there is no element than it stores -1).
580 This is not needed in this algorithm, but if we would call this algorithm
581 in a loop with increasing sets than it would make this algorithm incremental,
582 by not making the same matching test ever and ever again.
583 */
584
585 boolean match_set_of_internal(const Base_Type *value_ptr,
586 int value_start, int value_size,
587 const Restricted_Length_Template *template_ptr,
588 int template_start, int template_size,
589 match_function_t match_function,
590 type_of_matching match_type,
591 int* number_of_uncovered, int* pair_list,
592 unsigned int number_of_checked)
593 {
594 Matching_Table table(value_ptr, value_start, value_size,
595 template_ptr, template_start, template_size,
596 match_function);
597
598 // we have to use the reduced length of the template
599 // (not counting the asterisks)
600 int real_template_size = table.get_template_size();
601
602 // handling trivial cases:
603 //to be compatible with the previous version
604 // is a mistake if the user can't enter an asterisk as a set member
605 if(match_type == EXACT && real_template_size < template_size)
606 match_type = SUPERSET;
607
608 if(match_type == SUBSET && real_template_size < template_size)
609 {
610 return TRUE;
611 }
612
613 //if the element count does not match the matching mode then we are ready
614 if(match_type == SUBSET && value_size > real_template_size) return FALSE;
615 if(match_type == EXACT && value_size != real_template_size) return FALSE;
616 if(match_type == SUPERSET && value_size < real_template_size) return FALSE;
617
618 // if the template has no non-asterisk elements
619 if (real_template_size == 0) {
620 // if the template has only asterisks -> matches everything
621 if (template_size > 0) return TRUE;
622 // the empty template matches the empty value only
623 else return (value_size == 0 || match_type == SUPERSET);
624 }
625
626 // let's start the real work
627
628 // allocate some memory
629 table.create_matrix();
630
631 //if we need increamentality
632
633 if(pair_list != NULL)
634 for(int i = 0; i < template_size; i++)
635 {
636 //if we have values from a previous matching than use them
637 // instead of counting them out again
638 if(pair_list[i] >= 0)
639 {
640 table.set_paired(i, pair_list[i]);
641 table.set_covered(pair_list[i], i);
642 table.set_edge(i, pair_list[i], PAIRS);
643 }
644 }
645
646 for(int template_index = 0;
647 template_index < real_template_size;
648 template_index++)
649 {
650 if(table.is_paired(template_index))
651 continue;
652
653 boolean found_route = FALSE;
654 Tree_list tree(template_index);
655 for (int i = template_index; ; )
656 {
657 int j;
658 if(table.is_paired(i))
659 j = table.get_paired(i)+1;
660 else
661 j = number_of_checked;
662
663 for(; j < value_size; j++)
664 {
665 //if it is not covered
666 if(!table.is_covered(j))
667 {
668 //if it is not covered then it might be good
669 if (table.get_edge(i, j) == EDGE)
670 {
671 //update the values in the tree
672 // and in the other structures
673 int new_value_index = j;
674 int temp_value_index;
675 int actual_node;
676 boolean at_end = FALSE;
677 for( ; !at_end; )
678 {
679 at_end = tree.is_head();
680 actual_node = tree.actual_data();
681
682 temp_value_index = table.get_paired(actual_node);
683 if(temp_value_index != -1)
684 table.set_edge(temp_value_index,actual_node,EDGE);
685
686 table.set_paired(actual_node,new_value_index);
687
688 if(pair_list != NULL)
689 pair_list[actual_node] = new_value_index;
690
691 table.set_edge(actual_node, new_value_index, PAIRS);
692 table.set_covered(new_value_index,actual_node);
693
694 new_value_index = temp_value_index;
695 if(!at_end)
696 tree.back_step();
697 }
698
699 //if we need subset matching
700 // and we already matched every value
701 // then we have finished
702 if(match_type == SUBSET
703 && table.get_nof_covered() == value_size)
704 {
705 return TRUE;
706 }
707
708 found_route = TRUE;
709 break;
710 }
711 }
712 }
713 if (found_route) break;
714
715 //we get here if we couldn't find a new value for the template
716 // so we check if there is a covered value.
717 // if we find one then we try to find a new value for his
718 // pair template.
719 for(j = 0 ; j < value_size; j++)
720 {
721 if(table.is_covered(j) &&
722 table.get_edge(i,j) == EDGE &&
723 !tree.do_exists(j + real_template_size))
724 {
725 int temp_index = table.covered_by(j);
726 if(!tree.do_exists(temp_index))
727 {
728 tree.insert_data(temp_index);
729 }
730 }
731 }
732
733 if (!tree.end_of_list()) {
734 // continue with the next element
735 tree.step_forward();
736 i = tree.actual_data();
737 } else {
738 //couldn't find a matching value for a template
739 // this can only be allowed in SUBSET matching,
740 // otherwise there is no match
741 if(match_type == EXACT)
742 return FALSE;
743
744 //every template has to match in SUPERSET matching
745 if(match_type == SUPERSET)
746 {
747 //if we are not in permutation matching or don't need to count
748 // the number of unmatched templates than exit
749 if(number_of_uncovered == NULL)
750 return FALSE;
751 }
752
753 //if we are SUBSET matching
754 // then we have either returned true when we found
755 // a new value for the last template (so we can't get to here)
756 // or we just have to simply ignore this template
757 break;
758 }
759 }
760 }
761 //we only reach here if we have found pairs to every template or we
762 // are making a SUBSET match
763 // (or in SUPERSET we need the number of uncovered)
764 //the result depends on the number of pairs found
765
766 int number_of_pairs = table.get_nof_covered();
767
768 if(match_type == SUBSET)
769 {
770 if(number_of_pairs == value_size)
771 return TRUE;
772 else
773 return FALSE;
774 }
775
776 //here EXACT can only be true or we would have return false earlier
777 if(match_type == EXACT) return TRUE;
778
779 if(match_type == SUPERSET)
780 {
781 //we only return FALSE if we need the number of uncovered templates and
782 // there really were uncovered templates
783 if(number_of_uncovered != NULL && number_of_pairs != real_template_size)
784 {
785 *number_of_uncovered = real_template_size - number_of_pairs;
786 return FALSE;
787 }else{
788 return TRUE;
789 }
790 }
791
792 return FALSE;
793 }
794
795
796 //the real matching function, we don't wan't it to be seen from outside so
797 // it is not declared in the header, but called by permutation_match
798
799 /*
800 recursive_permutation_match implements a recursive algorithm to match
801 two arrays of values say A and B, where A can contain permutations and
802 asterisks.
803 A permutation is matched if there is a matching part of values in array B
804 with any order of the values in the permutation.
805
806 The algorithm:
807
808 The algorithm is recursive so we will give the general working for one
809 level, which is what all the levels do.
810
811 At each level the algorithm is called with some left over of both arrays
812 and tries to match them.
813
814 There are three different ways to go on each level:
815 -if A's leftover's first element is the beginning of a permutation
816 then a set_of like matching will take place. It is not exactly a set_of
817 matching because if there is a asterisk among the permutated elements
818 than we can'tknow how long part of B's array will match it.
819
820 So we try to find the smallest possible part of B's array which will be
821 a superset of the permutated elements. This is achieved by making set_of
822 matchings. When the superset is found, we call the algorithm for
823 the leftovers of the two arrays.
824
825 If the leftovers don't match, than we try matching a bigger part of B's
826 array with the permutated elements, till we find a size where the
827 leftovers match and we can return true, or we reach the maximal size
828 the permutation allows as to match with elements of B, in this case
829 we must return false.
830
831 -if A's leftover start with an asterisk which does not belong to a
832 permutation than it treated like a permutation, whose minimal size of
833 matching is 0 elements, and maximal size of matching is the whole
834 leftover array of B.
835
836 -else we have to make element-by-element matches.
837 if we match till the next asterisk or permutation start then we
838 make a recursive call with the elements from there
839 else we return false.
840
841 There are some speedups:
842 -in permutation matching:
843 -we estimate how small or large the matching set can be in
844 advance.
845 -to find the first matching set of B's elements we use the incremental
846 version of set matching.
847 -after finding a matching set we don't make any more set matches as
848 the increased set must still be a superset.
849 -if we fail in the element-by-element matching part than we don't return
850 with false, but try to find the first element of B which will match with
851 the last "unmatched" element of A. We give back this shift size to the
852 calling level so it can make a bigger jump forward (skipping the calls
853 that have no chance to match).
854 -if we in any part of the algorithm find that match can't possibly happen,
855 than we return to the calling level with NO_CHANCE. This way we can
856 end the algorithm without making those unnecessary checks.
857 */
858 static answer recursive_permutation_match(const Base_Type *value_ptr,
859 unsigned int value_start_index,
860 unsigned int value_size,
861 const Record_Of_Template *template_ptr,
862 unsigned int template_start_index,
863 unsigned int template_size,
864 unsigned int permutation_index,
865 match_function_t match_function,
866 unsigned int& shift_size)
867 {
868 unsigned int nof_permutations = template_ptr->get_number_of_permutations();
869 if (permutation_index > nof_permutations)
870 TTCN_error("Internal error: recursive_permutation_match: "
871 "invalid argument.");
872
873 if (permutation_index < nof_permutations &&
874 template_ptr->get_permutation_end(permutation_index) >
875 template_start_index + template_size)
876 TTCN_error("Internal error: recursive_permutation_match: wrong "
877 "permutation interval settings for permutation %d.",
878 permutation_index);
879
880 shift_size = 0;
881
882 //trivial cases
883 if(template_size == 0)
884 {
885 //reached the end of templates
886 // if we reached the end of values => good
887 // else => bad
888 if(value_size == 0)
889 return SUCCESS;
890 else
891 return FAILURE;
892 }
893
894 //are we at an asterisk or at the beginning of a permutation interval
895 boolean is_asterisk;
896 boolean permutation_begins = permutation_index < nof_permutations &&
897 template_start_index ==
898 template_ptr->get_permutation_start(permutation_index);
899
900 if (permutation_begins ||
901 match_function(value_ptr, -1, template_ptr, template_start_index))
902 {
903 unsigned int smallest_possible_size;
904 unsigned int largest_possible_size;
905 boolean has_asterisk;
906 boolean already_superset;
907 unsigned int permutation_size;
908
909 //check how many values might be associated with this permutation
910 //if we are at a permutation start
911 if (permutation_begins)
912 {
913 is_asterisk = FALSE;
914 permutation_size =
915 template_ptr->get_permutation_size(permutation_index);
916 smallest_possible_size = 0;
917 has_asterisk = FALSE;
918
919 //count how many non asterisk elements are in the permutation
920 for(unsigned int i = 0; i < permutation_size; i++)
921 {
922 if(match_function(value_ptr, -1, template_ptr,
923 i + template_start_index))
924 {
925 has_asterisk = TRUE;
926 }else{
927 smallest_possible_size++;
928 }
929 }
930
931 //the real permutation size is bigger then the value size
932 if(smallest_possible_size > value_size)
933 return NO_CHANCE;
934
935 //if the permutation has an asterisk then it can grow
936 if(has_asterisk)
937 {
938 largest_possible_size = value_size;
939
940 //if there are only asterisks in the permutation
941 if(smallest_possible_size == 0)
942 already_superset = TRUE;
943 else
944 already_superset = FALSE;
945 }else{
946 //without asterisks its size is fixed
947 largest_possible_size = smallest_possible_size;
948 already_superset = FALSE;
949 }
950 }else{
951 //or at an asterisk
952 is_asterisk = TRUE;
953 already_superset = TRUE;
954 permutation_size = 1;
955 smallest_possible_size = 0;
956 largest_possible_size = value_size;
957 has_asterisk = TRUE;
958 }
959
960 unsigned int temp_size = smallest_possible_size;
961
962 {
963 //this is to make match_set_of incremental,
964 // we store the already found pairs in this vector
965 // so we wouldn't try to find a pair for those templates again
966 // and we can set the covered state of values too
967 // to not waste memory it is only created if needed
968 int* pair_list = NULL;
969 unsigned int old_temp_size = 0;
970
971 if(!already_superset)
972 {
973 pair_list = new int[permutation_size];
974 for(unsigned int i = 0 ; i < permutation_size; i++)
975 {
976 //in the beginning we haven't found a template to any values
977 pair_list[i] = -1;
978 }
979 }
980
981 while(!already_superset)
982 {
983 //must be a permutation having other values than asterisks
984
985 int x = 0;
986
987 //our set matching is extended with 2 more parameters
988 // giving back how many templates
989 // (other than asterisk) couldn't be matched
990 // and setting / giving back the value-template pairs
991
992 boolean found = match_set_of_internal(value_ptr, value_start_index,
993 temp_size, template_ptr,
994 template_start_index, permutation_size,
995 match_function, SUPERSET, &x, pair_list,old_temp_size);
996
997 if(found)
998 {
999 already_superset = TRUE;
1000 }else{
1001 //as we didn't found a match we have to try
1002 // a larger set of values
1003 //x is the number of templates we couldn't find
1004 // a matching pair for
1005 // the next must be at least this big to fully cover
1006 // on the other side if it would be bigger than it might miss
1007 // the smallest possible match.
1008
1009 //if we can match with more values
1010 if(has_asterisk && temp_size + x <= largest_possible_size)
1011 {
1012 old_temp_size = temp_size;
1013 temp_size += x;
1014 }else{
1015 delete[] pair_list;
1016 return FAILURE; //else we failed
1017 }
1018 }
1019 }
1020
1021 delete[] pair_list;
1022 }
1023
1024 //we reach here only if we found a match
1025
1026 //can only go on recursively if we haven't reached the end
1027
1028 //reached the end of templates
1029 if(permutation_size == template_size)
1030 {
1031 if(has_asterisk || value_size == temp_size)
1032 return SUCCESS;
1033 else
1034 return FAILURE;
1035 }
1036
1037 for(unsigned int i = temp_size; i <= largest_possible_size;)
1038 {
1039 answer result;
1040
1041 if(is_asterisk)
1042 {
1043 //don't step the permutation index
1044 result = recursive_permutation_match(value_ptr,value_start_index+i,
1045 value_size - i, template_ptr,
1046 template_start_index +
1047 permutation_size,
1048 template_size -
1049 permutation_size,
1050 permutation_index,
1051 match_function, shift_size);
1052 }else{
1053 //try with the next permutation
1054 result = recursive_permutation_match(value_ptr,value_start_index+i,
1055 value_size - i, template_ptr,
1056 template_start_index +
1057 permutation_size,
1058 template_size - permutation_size,
1059 permutation_index + 1,
1060 match_function, shift_size);
1061 }
1062
1063 if(result == SUCCESS)
1064 return SUCCESS; //we finished
1065 else if(result == NO_CHANCE)
1066 return NO_CHANCE; //matching is not possible
1067 else if(i == value_size) //we failed
1068 {
1069 //if there is no chance of matching
1070 return NO_CHANCE;
1071 }else{
1072 i += shift_size > 1 ? shift_size : 1;
1073
1074 if(i > largest_possible_size)
1075 shift_size = i - largest_possible_size;
1076 else
1077 shift_size = 0;
1078 }
1079 }
1080
1081 //this level failed;
1082 return FAILURE;
1083 }else{
1084 //we are at the beginning of a non permutation, non asterisk interval
1085
1086 //the distance to the next permutation or the end of templates
1087 // so the longest possible match
1088 unsigned int distance;
1089
1090 if (permutation_index < nof_permutations)
1091 {
1092 distance = template_ptr->get_permutation_start(permutation_index)
1093 - template_start_index;
1094 }else{
1095 distance = template_size;
1096 }
1097
1098 //if there are no more values, but we still have templates
1099 // and the template is not an asterisk or a permutation start
1100 if(value_size == 0)
1101 return FAILURE;
1102
1103 //we try to match as many values as possible
1104 //an asterisk is handled like a 0 length permutation
1105 boolean good;
1106 unsigned int i = 0;
1107 do{
1108 good = match_function(value_ptr, value_start_index + i,
1109 template_ptr, template_start_index + i);
1110 i++;
1111 //bad stop: something can't be matched
1112 //half bad half good stop: the end of values is reached
1113 //good stop: matching on the full distance or till an asterisk
1114 }while(good && i < value_size && i < distance &&
1115 !match_function(value_ptr, -1, template_ptr,
1116 template_start_index + i));
1117
1118 //if we matched on the full distance or till an asterisk
1119 if(good && (i == distance ||
1120 match_function(value_ptr, -1, template_ptr,
1121 template_start_index + i)))
1122 {
1123 //reached the end of the templates
1124 if(i == template_size)
1125 {
1126 if(i < value_size)
1127 {
1128 //the next level would return FAILURE so we don't step it
1129 return FAILURE;
1130 }else{
1131 //i == value_size, so we matched everything
1132 return SUCCESS;
1133 }
1134 }else{
1135 //we reached the next asterisk or permutation,
1136 // so step to the next level
1137 return recursive_permutation_match(value_ptr,value_start_index + i,
1138 value_size - i,
1139 template_ptr,
1140 template_start_index + i,
1141 template_size - i,
1142 permutation_index,
1143 match_function, shift_size);
1144 }
1145 }else{
1146 //something bad happened, so we have to check how bad the situation is
1147 if( i == value_size)
1148 {
1149 //the aren't values left, meaning that the match is not possible
1150 return NO_CHANCE;
1151 }else{
1152 //we couldn't match, but there is still a chance of matching
1153
1154 //try to find a matching value for the last checked (and failed)
1155 // template.
1156 // smaller jumps would fail so we skip them
1157 shift_size = 0;
1158 i--;
1159 do{
1160 good = match_function(value_ptr,
1161 value_start_index + i + shift_size,
1162 template_ptr, template_start_index + i);
1163 shift_size++;
1164 }while(!good && i + shift_size < value_size);
1165
1166 if(good)
1167 {
1168 shift_size--;
1169 return FAILURE;
1170 }else{
1171 // the template can not be matched later
1172 return NO_CHANCE;
1173 }
1174 }
1175 }
1176 }
1177 }
1178
1179 /*
1180 outer function calling the real recursive_permutation_match
1181
1182 if we know that there is no need for the permutation matching
1183 (because there are no permutations in the array, or the whole array
1184 is just one permutation), than we call appropriate matching function
1185 instead of slower recursive_permutation_match.
1186 */
1187 boolean match_record_of(const Base_Type *value_ptr, int value_size,
1188 const Record_Of_Template *template_ptr,
1189 int template_size, match_function_t match_function)
1190 {
1191 if (value_ptr == NULL || value_size < 0 ||
1192 template_ptr == NULL || template_size < 0 ||
1193 template_ptr->get_selection() != SPECIFIC_VALUE)
1194 TTCN_error("Internal error: match_record_of: invalid argument.");
1195
1196 unsigned int nof_permutations = template_ptr->get_number_of_permutations();
1197 // use the simplified algorithm if the template does not contain permutation
1198 if (nof_permutations == 0)
1199 return match_array(value_ptr, value_size,
1200 template_ptr, template_size, match_function);
1201 // use 'set of' matching if all template elements are grouped into one
1202 // permutation
1203 if (nof_permutations == 1 && template_ptr->get_permutation_start(0) == 0 &&
1204 template_ptr->get_permutation_end(0) ==
1205 (unsigned int)(template_size - 1))
1206 return match_set_of(value_ptr, value_size, template_ptr, template_size,
1207 match_function);
1208
1209 unsigned int shift_size = 0;
1210 return recursive_permutation_match(value_ptr, 0, value_size, template_ptr,
1211 0, template_size, 0, match_function, shift_size) == SUCCESS;
1212 }
1213
1214 boolean match_set_of(const Base_Type *value_ptr, int value_size,
1215 const Restricted_Length_Template *template_ptr,
1216 int template_size, match_function_t match_function)
1217 {
1218 if (value_ptr == NULL || value_size < 0 ||
1219 template_ptr == NULL || template_size < 0)
1220 TTCN_error("Internal error: match_set_of: invalid argument.");
1221 type_of_matching match_type = EXACT;
1222 switch (template_ptr->get_selection()) {
1223 case SPECIFIC_VALUE:
1224 match_type = EXACT;
1225 break;
1226 case SUPERSET_MATCH:
1227 match_type = SUPERSET;
1228 break;
1229 case SUBSET_MATCH:
1230 match_type = SUBSET;
1231 break;
1232 default:
1233 TTCN_error("Internal error: match_set_of: invalid matching type.");
1234 }
1235 return match_set_of_internal(value_ptr, 0, value_size, template_ptr, 0,
1236 template_size, match_function, match_type, NULL, NULL, 0);
1237 }
1238
1239 void log_match_heuristics(const Base_Type *value_ptr, int value_size,
1240 const Restricted_Length_Template *template_ptr,
1241 int template_size,
1242 match_function_t match_function,
1243 log_function_t log_function)
1244 {
1245 if (value_ptr == NULL || value_size < 0 ||
1246 template_ptr == NULL || template_size < 0 ||
1247 template_ptr->get_selection() != SPECIFIC_VALUE)
1248 TTCN_error("Internal error: log_match_heuristics: invalid argument.");
1249
1250 if (value_size == 0 && template_size == 0) return;
1251
1252 if (!template_ptr->match_length(value_size)) {
1253 TTCN_Logger::log_event("Length restriction cannot be satisfied. ");
1254 return;
1255 }
1256
1257 int asterisks_found = 0;
1258 for (int i = 0; i < template_size; i++)
1259 {
1260 // If j == -1, check whether the template element is an asterisk.
1261 // There is no problem if an asterisk has no matching pair.
1262 if (match_function(value_ptr, -1, template_ptr, i))
1263 {
1264 asterisks_found++;
1265 }
1266 }
1267
1268 if(value_size < template_size - asterisks_found){
1269 TTCN_Logger::print_logmatch_buffer();
1270 if(asterisks_found == 0){
1271 TTCN_Logger::log_event(" Too few elements in value are present: %d was expected instead of %d", template_size, value_size);
1272 }else{
1273 TTCN_Logger::log_event(" Too few value elements are present in value: at least %d was expected instead of %d", template_size-asterisks_found, value_size);
1274 }
1275 return;
1276 }else if(asterisks_found == 0 && value_size > template_size){
1277 TTCN_Logger::print_logmatch_buffer();
1278 TTCN_Logger::log_event(" Too many elements are present in value: %d was expected instead of %d", template_size, value_size);
1279 return;
1280 }
1281
1282 if (value_size == 0 || template_size == 0) return;
1283
1284 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity()){
1285 TTCN_Logger::log_event_str(" Some hints to find the reason of mismatch: ");
1286 TTCN_Logger::log_event_str("{ value elements that have no pairs in the template: ");
1287 }
1288
1289 boolean value_found = FALSE;
1290 int nof_unmatched_values = 0;
1291 bool *unmatched_values = new bool[value_size];
1292 for (int i = 0; i < value_size; i++)
1293 {
1294 boolean pair_found = FALSE;
1295 for (int j = 0; j < template_size; j++)
1296 {
1297 if (match_function(value_ptr, i, template_ptr, j))
1298 {
1299 pair_found = TRUE;
1300 break;
1301 }
1302 }
1303
1304 unmatched_values[i] = !pair_found;
1305 if (!pair_found)
1306 {
1307 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity()){
1308 if (value_found)
1309 TTCN_Logger::log_event_str(", ");
1310 else
1311 value_found = TRUE;
1312
1313 log_function(value_ptr, NULL, i, 0);
1314 TTCN_Logger::log_event(" at index %d", i);
1315 }
1316 nof_unmatched_values++;
1317 }
1318 }
1319
1320 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity()){
1321 if (!value_found) TTCN_Logger::log_event_str("none");
1322 TTCN_Logger::log_event_str(", template elements that have no pairs in "
1323 "the value: ");
1324 }
1325
1326 boolean template_found = FALSE;
1327 int nof_unmatched_templates = 0;
1328 bool *unmatched_templates = new bool[template_size];
1329 for (int i = 0; i < template_size; i++)
1330 {
1331 boolean pair_found = FALSE;
1332 // if j == -1 it is checked whether the template element is an
1333 // asterisk there is no problem if an asterisk has no matching
1334 // pair
1335 for (int j = -1; j < value_size; j++)
1336 {
1337 if (match_function(value_ptr, j, template_ptr, i))
1338 {
1339 pair_found = TRUE;
1340 break;
1341 }
1342 }
1343 unmatched_templates[i] = !pair_found;
1344 if (!pair_found)
1345 {
1346 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity()){
1347 if (template_found)
1348 TTCN_Logger::log_event_str(", ");
1349 else
1350 template_found = TRUE;
1351
1352 log_function(NULL, template_ptr, 0, i);
1353 TTCN_Logger::log_event(" at index %d", i);
1354 }
1355 nof_unmatched_templates++;
1356 }
1357 }
1358
1359 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity()){
1360 if (!template_found) TTCN_Logger::log_event_str("none");
1361
1362 TTCN_Logger::log_event_str(", matching value <-> template index pairs: ");
1363 boolean pair_found = FALSE;
1364 for (int i = 0; i < value_size; i++)
1365 {
1366 for (int j = 0; j < template_size; j++)
1367 {
1368 if (match_function(value_ptr, i, template_ptr, j))
1369 {
1370 if (pair_found)
1371 TTCN_Logger::log_char(',');
1372 else {
1373 TTCN_Logger::log_char('{');
1374 pair_found = TRUE;
1375 }
1376 TTCN_Logger::log_event(" %d <-> %d", i, j);
1377 }
1378 }
1379 }
1380 if (pair_found) TTCN_Logger::log_event_str(" }");
1381 else TTCN_Logger::log_event_str("none");
1382 }
1383
1384 if(nof_unmatched_templates > 0 && nof_unmatched_values > 0){
1385 if(TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity()){
1386 int previous_size = TTCN_Logger::get_logmatch_buffer_len();
1387 for (int i = 0; i < value_size; i++)
1388 {
1389 if(unmatched_values[i]){
1390 for (int j = 0; j < template_size; j++)
1391 {
1392 if(unmatched_templates[j]){
1393 TTCN_Logger::log_logmatch_info("[%d <-> %d]", i, j);
1394 log_function(value_ptr, template_ptr, i, j);
1395
1396 TTCN_Logger::set_logmatch_buffer_len(previous_size);
1397 }
1398 }
1399 }
1400 }
1401 }else{
1402 TTCN_Logger::log_event_str(", matching unmatched value <-> template index pairs: ");
1403 char sep = '{';
1404 for (int i = 0; i < value_size; i++)
1405 {
1406 if(unmatched_values[i]){
1407 for (int j = 0; j < template_size; j++)
1408 {
1409 if(unmatched_templates[j]){
1410 TTCN_Logger::log_event("%c %d <-> %d:{ ", sep, i, j);
1411 if('{' == sep){
1412 sep = ',';
1413 }
1414 log_function(value_ptr, template_ptr, i, j);
1415 TTCN_Logger::log_event_str(" }");
1416 }
1417 }
1418 }
1419 }
1420
1421 TTCN_Logger::log_event_str(" }");
1422 }
1423 }
1424 delete [] unmatched_values;
1425 delete [] unmatched_templates;
1426 if(TTCN_Logger::VERBOSITY_COMPACT != TTCN_Logger::get_matching_verbosity())
1427 TTCN_Logger::log_event_str(" }");
1428 }
This page took 0.08932 seconds and 5 git commands to generate.