Get metadata for bejReal type
Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ib5de2d4fde4a129cb32988268c3289ba06572b16
diff --git a/src/bej_encoder_metadata.c b/src/bej_encoder_metadata.c
index 3e273a0..098c5e7 100644
--- a/src/bej_encoder_metadata.c
+++ b/src/bej_encoder_metadata.c
@@ -3,11 +3,17 @@
#include "bej_common.h"
#include "bej_dictionary.h"
+#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/**
+ * @brief Maximum digits supported in the fractional part of a real number.
+ */
+#define BEJ_REAL_PRECISION 16
+
+/**
* @brief bejTupleL size of an integer.
*
* Maximum bytes possible for an integer is 8. Therefore to encode the length of
@@ -24,6 +30,11 @@
#define BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL 2
/**
+ * @brief bejTupleF size.
+ */
+#define BEJ_TUPLE_F_SIZE 1
+
+/**
* @brief Check the name is an annotation type name.
*
* @param[in] name - property name.
@@ -187,7 +198,7 @@
// S: Size needed for encoding sequence number.
node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
// F: Size of the format byte is 1.
- node->leaf.metaData.sflSize += 1;
+ node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
// L: Length needed for the value.
node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
// V: Bytes used for the value.
@@ -211,7 +222,7 @@
// S: Size needed for encoding sequence number.
node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
// F: Size of the format byte is 1.
- node->leaf.metaData.sflSize += 1;
+ node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
// L: Length needed for the string including the NULL character. Length is
// in nnint format.
size_t strLenWithNull = strlen(node->value) + 1;
@@ -221,6 +232,87 @@
return 0;
}
+static int bejUpdateRealMetaData(const struct BejDictionaries* dictionaries,
+ const uint8_t* parentDictionary,
+ struct RedfishPropertyLeafReal* node,
+ uint16_t nodeIndex,
+ uint16_t dictStartingOffset)
+{
+ uint32_t sequenceNumber;
+ RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
+ dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex,
+ dictStartingOffset, &sequenceNumber, NULL, NULL));
+ node->leaf.metaData.sequenceNumber = sequenceNumber;
+
+ if (node->value > (double)INT64_MAX)
+ {
+ // TODO: We should use the exponent.
+ fprintf(
+ stderr,
+ "Need to add support to encode double value larger than INT64_MAX\n");
+ return -1;
+ }
+
+ // Calculate the size for encoding this in a SFLV tuple.
+ // S: Size needed for encoding sequence number.
+ node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
+ // F: Size of the format byte is 1.
+ node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
+ // We need to breakdown the real number to bejReal type to determine the
+ // length. We are not gonna add an exponent. It will only be the whole part
+ // and the fraction part. Get the whole part
+ double originalWhole;
+ double originalFract = modf(node->value, &originalWhole);
+
+ // Convert the fraction to a whole value for encoding.
+ // Create a new value by multiplying the original fraction by 10. Do this
+ // until the fraction of the new value is 0 or we reach the precision. Eg
+ // 0.00105: This fraction value has two leading zeros. We will keep
+ // multiplying this by 10 until the fraction of the result of that
+ // multiplication is 0.
+ double originalFactConvertedToWhole = fabs(originalFract);
+ double fract = originalFract;
+ double intPart;
+ uint32_t leadingZeros = 0;
+ uint32_t precision = 0;
+ while (fract != 0 && precision < BEJ_REAL_PRECISION)
+ {
+ originalFactConvertedToWhole = originalFactConvertedToWhole * 10;
+ fract = modf(originalFactConvertedToWhole, &intPart);
+ // If the integer portion is 0, that means we still have leading zeros.
+ if (intPart == 0)
+ {
+ ++leadingZeros;
+ }
+ ++precision;
+ }
+ node->bejReal.whole = (int64_t)originalWhole;
+ node->bejReal.zeroCount = leadingZeros;
+ node->bejReal.fract = (int64_t)originalFactConvertedToWhole;
+ // We are omitting exp. So the exp length should be 0.
+ node->bejReal.expLen = 0;
+ node->bejReal.exp = 0;
+
+ // Calculate the sizes needed for storing bejReal fields.
+ // nnint for the length of the "whole" value.
+ node->leaf.metaData.vSize = BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
+ // Length needed for the "whole" value.
+ node->leaf.metaData.vSize += bejIntLengthOfValue((int64_t)originalWhole);
+ // nnint for leading zero count.
+ node->leaf.metaData.vSize += bejNnintEncodingSizeOfUInt(leadingZeros);
+ // nnint for the factional part.
+ node->leaf.metaData.vSize +=
+ bejNnintEncodingSizeOfUInt((int64_t)originalFactConvertedToWhole);
+ // nnint for the exp length. We are omitting exp. So the exp length should
+ // be 0.
+ node->leaf.metaData.vSize += bejNnintEncodingSizeOfUInt(0);
+
+ // L: nnint for the size needed for encoding the bejReal value.
+ node->leaf.metaData.sflSize +=
+ bejNnintEncodingSizeOfUInt(node->leaf.metaData.vSize);
+ return 0;
+}
+
static int bejUpdateEnumMetaData(const struct BejDictionaries* dictionaries,
const uint8_t* parentDictionary,
struct RedfishPropertyLeafEnum* node,
@@ -264,7 +356,7 @@
// S: Size needed for encoding sequence number.
node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
// F: Size of the format byte is 1.
- node->leaf.metaData.sflSize += 1;
+ node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
// V: Bytes used for the value.
node->leaf.metaData.vSize =
bejNnintEncodingSizeOfUInt(enumValueProperty->sequenceNumber);
@@ -290,7 +382,7 @@
// S: Size needed for encoding sequence number.
node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
// F: Size of the format byte is 1.
- node->leaf.metaData.sflSize += 1;
+ node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
// L: Length needed for the value.
node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL;
// V: Bytes used for the value; 0x00 or 0xFF.
@@ -329,6 +421,11 @@
dictionaries, parentDictionary, childPtr, childIndex,
dictStartingOffset));
break;
+ case bejReal:
+ RETURN_IF_IERROR(
+ bejUpdateRealMetaData(dictionaries, parentDictionary, childPtr,
+ childIndex, dictStartingOffset));
+ break;
case bejEnum:
RETURN_IF_IERROR(
bejUpdateEnumMetaData(dictionaries, parentDictionary, childPtr,