tag2member


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@14 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/ber_decoder.c b/skeletons/ber_decoder.c
index ab8d671..09211ed 100644
--- a/skeletons/ber_decoder.c
+++ b/skeletons/ber_decoder.c
@@ -54,7 +54,7 @@
 
 	/*
 	 * So what does all this tags_impl_skip stuff mean?
-	 * Imagine two types,
+	 * Imagine the two types,
 	 * 	A ::= [5] IMPLICIT	T
 	 * 	B ::= [2] EXPLICIT	T
 	 * Where T is defined as
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index 1ecbbce..d1beff4 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -67,8 +67,8 @@
  */
 static int
 _search4tag(const void *ap, const void *bp) {
-	const asn1_CHOICE_tag2member_t *a = ap;
-	const asn1_CHOICE_tag2member_t *b = bp;
+	const asn1_TYPE_tag2member_t *a = ap;
+	const asn1_TYPE_tag2member_t *b = bp;
 	int a_class = BER_TAG_CLASS(a->el_tag);
 	int b_class = BER_TAG_CLASS(b->el_tag);
 
@@ -180,8 +180,8 @@
 		}
 
 		do {
-			asn1_CHOICE_tag2member_t *t2m;
-			asn1_CHOICE_tag2member_t key;
+			asn1_TYPE_tag2member_t *t2m;
+			asn1_TYPE_tag2member_t key;
 
 			key.el_tag = tlv_tag;
 			t2m = bsearch(&key, specs->tag2el, specs->tag2el_count,
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index 70766e9..1308bd4 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -15,16 +15,10 @@
 	int optional;			/* Whether the element is optional */
 	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
 	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t
-		*type;			/* Member type descriptor */
+	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
 	char *name;			/* ASN.1 identifier of the element */
 } asn1_CHOICE_element_t;
 
-typedef struct asn1_CHOICE_tag2member_s {
-	ber_tlv_tag_t el_tag;	/* Outmost tag of the member */
-	int el_no;		/* Index of the associated member, base 0 */
-} asn1_CHOICE_tag2member_t;
-
 typedef struct asn1_CHOICE_specifics_s {
 	/*
 	 * Target structure description.
@@ -43,7 +37,7 @@
 	/*
 	 * Tags to members mapping table.
 	 */
-	asn1_CHOICE_tag2member_t *tag2el;
+	asn1_TYPE_tag2member_t *tag2el;
 	int tag2el_count;
 
 	/*
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 7168967..5c47df0 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -3,6 +3,7 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <constr_SEQUENCE.h>
+#include <assert.h>
 
 /*
  * Number of bytes left for this structure.
@@ -62,6 +63,35 @@
 	( ((memb_idx) > (specs)->ext_after)	\
 	&&((memb_idx) < (specs)->ext_before))
 
+
+/*
+ * Tags are canonically sorted in the tag2element map.
+ */
+static int
+_t2e_cmp(const void *ap, const void *bp) {
+	const asn1_TYPE_tag2member_t *a = ap;
+	const asn1_TYPE_tag2member_t *b = bp;
+	int a_class = BER_TAG_CLASS(a->el_tag);
+	int b_class = BER_TAG_CLASS(b->el_tag);
+
+	if(a_class == b_class) {
+		ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
+		ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
+
+		if(a_value == b_value)
+			return 0;
+		else if(a_value < b_value)
+			return -1;
+		else
+			return 1;
+	} else if(a_class < b_class) {
+		return -1;
+	} else {
+		return 1;
+	}
+}
+
+
 /*
  * The decoder of the SEQUENCE type.
  */
@@ -151,6 +181,7 @@
 		void *memb_ptr2;	/* Pointer to that pointer */
 		ssize_t tag_len;	/* Length of TLV's T */
 		int opt_edx_end;	/* Next non-optional element */
+		int use_bsearch;
 		int n;
 
 		if(ctx->step & 1)
@@ -196,9 +227,15 @@
 		/*
 		 * Find the next available type with this tag.
 		 */
+		use_bsearch = 0;
 		opt_edx_end = edx + elements[edx].optional + 1;
 		if(opt_edx_end > specs->elements_count)
 			opt_edx_end = specs->elements_count;	/* Cap */
+		else if(opt_edx_end - edx > 5) {
+			/* Limit the scope of linear search */
+			opt_edx_end = edx + 5;
+			use_bsearch = 1;
+		}
 		for(n = edx; n < opt_edx_end; n++) {
 			if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) {
 				/*
@@ -207,10 +244,39 @@
 				 * Reposition over the right element.
 				 */
 				edx = n;
-				ctx->step = 2 * edx;	/* Remember! */
+				ctx->step = 1 + 2 * edx;	/* Remember! */
+				goto microphase2;
+			} else if(elements[n].tag == (ber_tlv_tag_t)-1) {
+				use_bsearch = 1;
 				break;
 			}
 		}
+		if(use_bsearch) {
+			/*
+			 * Resorch to a binary search over
+			 * sorted array of tags.
+			 */
+			asn1_TYPE_tag2member_t *t2m;
+			asn1_TYPE_tag2member_t key;
+			key.el_tag = tlv_tag;
+			t2m = bsearch(&key, specs->tag2el, specs->tag2el_count,
+				sizeof(specs->tag2el[0]), _t2e_cmp);
+			if(t2m && t2m->el_no >= edx) {
+				/*
+				 * Rewind to the first element with that tag,
+				 * `cause bsearch() does not guarantee order.
+				 */
+				while(t2m > specs->tag2el
+					&& BER_TAGS_EQUAL(tlv_tag,
+						t2m[-1].el_tag)
+					&& t2m[-1].el_no >= edx)
+					t2m++;
+				edx = t2m->el_no;
+				ctx->step = 1 + 2 * edx;
+				goto microphase2;
+			}
+			n = opt_edx_end;
+		}
 		if(n == opt_edx_end) {
 			/*
 			 * If tag is unknown, it may be either
@@ -222,8 +288,9 @@
 			if(!IN_EXTENSION_GROUP(specs, edx)) {
 				ASN_DEBUG("Unexpected tag %s",
 					ber_tlv_tag_string(tlv_tag));
-				ASN_DEBUG("Expected tag %s%s",
+				ASN_DEBUG("Expected tag %s (%s)%s",
 					ber_tlv_tag_string(elements[edx].tag),
+					elements[edx].name,
 					elements[edx].optional
 						?" or alternatives":"");
 				RETURN(RC_FAIL);
@@ -389,6 +456,7 @@
 	RETURN(RC_OK);
 }
 
+
 /*
  * The DER encoder of the SEQUENCE type.
  */
@@ -574,7 +642,7 @@
 		const void *memb_ptr;
 
 		if(elm->optional) {
-			memb_ptr = *(const void **)((const char *)sptr + elm->memb_offset);
+			memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
 			if(!memb_ptr) continue;
 		} else {
 			memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
index c15729c..17754bb 100644
--- a/skeletons/constr_SEQUENCE.h
+++ b/skeletons/constr_SEQUENCE.h
@@ -15,8 +15,7 @@
 	int optional;			/* Whether the element is optional */
 	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
 	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t
-		*type;			/* Member type descriptor */
+	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
 	char *name;			/* ASN.1 identifier of the element */
 } asn1_SEQUENCE_element_t;
 
@@ -34,6 +33,12 @@
 	int elements_count;
 
 	/*
+	 * Tags to members mapping table (sorted).
+	 */
+	asn1_TYPE_tag2member_t *tag2el;
+	int tag2el_count;
+
+	/*
 	 * Description of an extensions group.
 	 */
 	int ext_after;	/* Extensions start after this member */
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index d0cac1d..0385722 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -61,8 +61,8 @@
  */
 static int
 _t2e_cmp(const void *ap, const void *bp) {
-	const asn1_SET_tag2member_t *a = ap;
-	const asn1_SET_tag2member_t *b = bp;
+	const asn1_TYPE_tag2member_t *a = ap;
+	const asn1_TYPE_tag2member_t *b = bp;
 	int a_class = BER_TAG_CLASS(a->el_tag);
 	int b_class = BER_TAG_CLASS(b->el_tag);
 
@@ -225,8 +225,8 @@
 			 * but is not strongly anticipated either.
 			 */
 		} else {
-			asn1_SET_tag2member_t *t2m;
-			asn1_SET_tag2member_t key;
+			asn1_TYPE_tag2member_t *t2m;
+			asn1_TYPE_tag2member_t key;
 
 			key.el_tag = tlv_tag;
 			t2m = bsearch(&key, specs->tag2el, specs->tag2el_count,
@@ -430,7 +430,7 @@
 	size_t computed_size = 0;
 	der_enc_rval_t my_erval;
 	int t2m_build_own = (specs->tag2el_count != specs->elements_count);
-	asn1_SET_tag2member_t *t2m;
+	asn1_TYPE_tag2member_t *t2m;
 	int t2m_count;
 	ssize_t ret;
 	int edx;
diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h
index c0ac07f..8cb3fa8 100644
--- a/skeletons/constr_SET.h
+++ b/skeletons/constr_SET.h
@@ -15,19 +15,10 @@
 	int optional;			/* Whether the element is optional */
 	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
 	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t
-		*type;			/* Member type descriptor */
+	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
 	char *name;			/* ASN.1 identifier of the element */
 } asn1_SET_element_t;
 
-/*
- * Map between the outmost tag of the element and the corresponding
- * element's index.
- */
-typedef struct asn1_SET_tag2member_s {
-	ber_tlv_tag_t el_tag;	/* Outmost tag of the member */
-	int el_no;		/* Index of the associated member, base 0 */
-} asn1_SET_tag2member_t;
 
 typedef struct asn1_SET_specifics_s {
 	/*
@@ -46,7 +37,7 @@
 	/*
 	 * Tags to members mapping table (sorted).
 	 */
-	asn1_SET_tag2member_t *tag2el;
+	asn1_TYPE_tag2member_t *tag2el;
 	int tag2el_count;
 
 	/*
diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h
index 814774d..e2c6d8f 100644
--- a/skeletons/constr_SET_OF.h
+++ b/skeletons/constr_SET_OF.h
@@ -9,8 +9,7 @@
 
 typedef struct asn1_SET_OF_element_s {
 	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
-	asn1_TYPE_descriptor_t
-		*type;			/* Member type descriptor */
+	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
 } asn1_SET_OF_element_t;
 
 typedef struct asn1_SET_OF_specifics_s {
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index c7cfb22..5c00104 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -84,6 +84,16 @@
 } asn1_TYPE_descriptor_t;
 
 /*
+ * BER tag to element number mapping.
+ */
+typedef struct asn1_TYPE_tag2member_s {
+	ber_tlv_tag_t el_tag;	/* Outmost tag of the member */
+	int el_no;		/* Index of the associated member, base 0 */
+} asn1_TYPE_tag2member_t;
+
+
+
+/*
  * This function is a wrapper around (td)->print_struct, which prints out
  * the contents of the target language's structure (struct_ptr) into the
  * file pointer (stream) in human readable form.