encoding: In BinaryXmlDecoder, cache the result of peekDTag for a speedup when decoding optional elements.
diff --git a/CHANGELOG b/CHANGELOG
index 30089dc..5103e0b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@
* MetaInfo: Added setFinalBlockID for Name::Component, remove unused setFinalBlockID which take uint8_t*, etc.
* Fix clang compiler warnings: Include headers, parentheses and cast explicitly.
* Moved class ExcludeEntry to inner class Exclude::Entry.
+* In BinaryXmlDecoder, cache the result of peekDTag for a speedup when decoding optional elements.
Documentation
* Move instructions for running ./autogen.sh from configure.ac to the Development section of INSTALL.
diff --git a/src/c/encoding/binary-xml-decoder.c b/src/c/encoding/binary-xml-decoder.c
index 6a20e94..d3b4d22 100644
--- a/src/c/encoding/binary-xml-decoder.c
+++ b/src/c/encoding/binary-xml-decoder.c
@@ -86,17 +86,27 @@
ndn_Error ndn_BinaryXmlDecoder_readElementStartDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag)
{
- ndn_Error error;
- unsigned int type;
- unsigned int value;
- if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value)))
- return error;
-
- if (type != ndn_BinaryXml_DTAG)
- return NDN_ERROR_header_type_is_not_a_DTAG;
-
- if (value != expectedTag)
- return NDN_ERROR_did_not_get_the_expected_DTAG;
+ if (self->offset == self->previouslyPeekedDTagStartOffset) {
+ // peekDTag already decoded this DTag.
+ if (self->previouslyPeekedDTag != expectedTag)
+ return NDN_ERROR_did_not_get_the_expected_DTAG;
+
+ // Fast forward past the header.
+ self->offset = self->previouslyPeekedDTagEndOffset;
+ }
+ else {
+ ndn_Error error;
+ unsigned int type;
+ unsigned int value;
+ if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value)))
+ return error;
+
+ if (type != ndn_BinaryXml_DTAG)
+ return NDN_ERROR_header_type_is_not_a_DTAG;
+
+ if (value != expectedTag)
+ return NDN_ERROR_did_not_get_the_expected_DTAG;
+ }
return NDN_ERROR_success;
}
@@ -114,27 +124,39 @@
ndn_Error ndn_BinaryXmlDecoder_peekDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int *gotExpectedTag)
{
- // Default to 0.
- *gotExpectedTag = 0;
+ if (self->offset == self->previouslyPeekedDTagStartOffset)
+ // We already decoded this DTag.
+ *gotExpectedTag = (self->previouslyPeekedDTag == expectedTag ? 1 : 0);
+ else {
+ // Default to 0.
+ *gotExpectedTag = 0;
- // First check if it is an element close (which cannot be the expected tag).
- if (self->offset >= self->inputLength)
- return NDN_ERROR_read_past_the_end_of_the_input;
- if (unsafeGetOctet(self) == ndn_BinaryXml_CLOSE)
- return NDN_ERROR_success;
+ // First check if it is an element close (which cannot be the expected tag).
+ if (self->offset >= self->inputLength)
+ return NDN_ERROR_read_past_the_end_of_the_input;
+ if (unsafeGetOctet(self) == ndn_BinaryXml_CLOSE)
+ return NDN_ERROR_success;
- unsigned int type;
- unsigned int value;
- size_t saveOffset = self->offset;
- ndn_Error error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value);
- // Restore offset.
- self->offset = saveOffset;
-
- if (error)
- return error;
-
- if (type == ndn_BinaryXml_DTAG && value == expectedTag)
- *gotExpectedTag = 1;
+ unsigned int type;
+ unsigned int value;
+ size_t saveOffset = self->offset;
+ ndn_Error error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value);
+ // readElementStartDTag will use this to fast forward.
+ self->previouslyPeekedDTagEndOffset = self->offset;
+ // Restore offset.
+ self->offset = saveOffset;
+
+ if (error)
+ return error;
+
+ if (type == ndn_BinaryXml_DTAG) {
+ self->previouslyPeekedDTagStartOffset = saveOffset;
+ self->previouslyPeekedDTag = value;
+
+ if (value == expectedTag)
+ *gotExpectedTag = 1;
+ }
+ }
return NDN_ERROR_success;
}
diff --git a/src/c/encoding/binary-xml-decoder.h b/src/c/encoding/binary-xml-decoder.h
index 38fd450..5072b97 100644
--- a/src/c/encoding/binary-xml-decoder.h
+++ b/src/c/encoding/binary-xml-decoder.h
@@ -19,6 +19,10 @@
uint8_t *input;
size_t inputLength;
size_t offset;
+ // peekDTag sets and checks these, and readElementStartDTag uses them to avoid reading again.
+ size_t previouslyPeekedDTagStartOffset;
+ size_t previouslyPeekedDTagEndOffset;
+ unsigned int previouslyPeekedDTag;
};
static inline void ndn_BinaryXmlDecoder_initialize(struct ndn_BinaryXmlDecoder *self, uint8_t *input, size_t inputLength)
@@ -26,6 +30,7 @@
self->input = input;
self->inputLength = inputLength;
self->offset = 0;
+ self->previouslyPeekedDTagStartOffset = (size_t)-1;
}
/**