Skip to content

Commit 69f1ff9

Browse files
Merge pull request #60 from LarsMattsson/master
Fix for issue #59 - Optional None Operator encoded incorrect.
2 parents 1be6c37 + 7f85d15 commit 69f1ff9

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

src/mfast/coder/encoder/encoder_field_operator.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,14 @@ class no_operator : public encoder_field_operator,
7575
template <typename T>
7676
void encode_impl(const T &cref, fast_ostream &stream,
7777
encoder_presence_map & /* pmap */) const {
78-
stream << cref;
78+
if (cref.absent())
79+
{
80+
stream.encode_null();
81+
}
82+
else
83+
{
84+
stream << cref;
85+
}
7986

8087
// Fast Specification 1.1, page 22
8188
//

src/mfast/coder/encoder/fast_encoder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ void fast_encoder_impl::visit(message_cref cref, bool force_reset) {
196196
aggregate_cref message(cref.field_storage(0), instruction);
197197

198198
for (auto &&field : message)
199-
if (field.present())
199+
if (field.present() || field.instruction()->field_operator() == operator_none)
200200
apply_accessor(*this, field);
201201

202202
pmap.commit();

tests/encoder_operator_test.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,43 @@ TEST_CASE("test the encoding of fast operator none","[operator_none_test]")
206206
ext_cref<uint64_cref, none_operator_tag, optional_with_initial_value_tag >(result),
207207
CHANGE_PREVIOUS_VALUE, &allocator ) );
208208

209+
210+
211+
212+
213+
}
214+
{
215+
//Test of Appendix 3.1.2- Optonal uint64 none operator values.
216+
uint64_field_instruction inst(operator_none,
217+
presence_optional,
218+
1,
219+
"test_uint64", "",
220+
nullptr,
221+
int_value_storage<uint64_t>(UINT64_MAX));
222+
inst.construct_value(storage, &allocator);
223+
224+
225+
uint64_mref result(&allocator, &storage, &inst);
226+
result.as(0);
227+
228+
REQUIRE(encode_mref("\x80\x81", result, CHANGE_PREVIOUS_VALUE));
229+
inst.prev_value().defined(false); // reset the previous value to undefined again
230+
231+
result.as(1);
232+
233+
REQUIRE(encode_mref("\x80\x82", result, CHANGE_PREVIOUS_VALUE));
234+
235+
REQUIRE(encode_ext_cref("\x80\x82",
236+
ext_cref<uint64_cref, none_operator_tag, optional_with_initial_value_tag >(result),
237+
CHANGE_PREVIOUS_VALUE, &allocator));
238+
239+
240+
241+
242+
243+
244+
245+
209246
}
210247
{
211248
uint64_field_instruction inst(operator_none,
@@ -940,6 +977,66 @@ TEST_CASE("test the encoding of fast operator delta for decimal","[operator_delt
940977
}
941978
}
942979

980+
TEST_CASE("test the encoding of fast no operator for ascii string", "[operator_none_ascii_encode_test]")
981+
{
982+
debug_allocator alloc;
983+
value_storage storage;
984+
985+
{ // testing Option assci field with no operator
986+
const char* default_value = "initial_string";
987+
ascii_field_instruction inst(operator_none,
988+
presence_optional,
989+
1,
990+
"test_ascii", "",
991+
nullptr,
992+
string_value_storage());
993+
994+
inst.construct_value(storage, &alloc);
995+
996+
ascii_string_mref result(&alloc, &storage, &inst);
997+
998+
// If a field is optional and has no field operator, it is encoded with a
999+
// nullable representation and the NULL is used to represent absence of a
1000+
// value. It will not occupy any bits in the presence map.'
1001+
1002+
1003+
result.absent();
1004+
REQUIRE(encode_mref("\x80\x80", result, CHANGE_PREVIOUS_VALUE));
1005+
inst.prev_value().defined(false);
1006+
REQUIRE(encode_ext_cref("\x80\x80",
1007+
ext_cref<ascii_string_cref, none_operator_tag, mandatory_with_initial_value_tag>(result),
1008+
CHANGE_PREVIOUS_VALUE, &alloc));
1009+
inst.destruct_value(storage, &alloc);
1010+
inst.destruct_value(inst.prev_value(), &alloc);
1011+
}
1012+
1013+
{ // testing mandatory field with initial value
1014+
const char* default_value = "initial_string";
1015+
ascii_field_instruction inst(operator_none,
1016+
presence_mandatory,
1017+
1,
1018+
"test_ascii", "",
1019+
nullptr,
1020+
string_value_storage(default_value));
1021+
1022+
inst.construct_value(storage, &alloc);
1023+
1024+
ascii_string_mref result(&alloc, &storage, &inst);
1025+
1026+
//If a field is mandatory and has no field operator, it will not occupy any bit in the presence map and its value must always appear in the stream.
1027+
1028+
result.as("initial_value");
1029+
REQUIRE(encode_mref("\x80\x69\x6e\x69\x74\x69\x61\x6c\x5f\x76\x61\x6c\x75\xe5", result, CHANGE_PREVIOUS_VALUE));
1030+
inst.prev_value().defined(false);
1031+
REQUIRE(encode_ext_cref("\x80\x69\x6e\x69\x74\x69\x61\x6c\x5f\x76\x61\x6c\x75\xe5",
1032+
ext_cref<ascii_string_cref, none_operator_tag, mandatory_with_initial_value_tag>(result),
1033+
CHANGE_PREVIOUS_VALUE, &alloc));
1034+
inst.destruct_value(storage, &alloc);
1035+
inst.destruct_value(inst.prev_value(), &alloc);
1036+
}
1037+
1038+
1039+
}
9431040
TEST_CASE("test the encoding of fast operator delta for ascii string","[operator_delta_ascii_encode_test]")
9441041
{
9451042
debug_allocator alloc;

0 commit comments

Comments
 (0)