Skip to content

Commit a01ec0c

Browse files
Fix Issue #74
1 parent a7c5add commit a01ec0c

File tree

3 files changed

+98
-10
lines changed

3 files changed

+98
-10
lines changed

src/mfast/coder/encoder/encoder_field_operator.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ class copy_or_increment_operator_impl : public mfast::detail::codec_helper {
208208
template <typename T>
209209
void encode_impl(const T &cref, fast_ostream &stream,
210210
encoder_presence_map &pmap) const {
211-
211+
212212
value_storage previous = previous_value_of(cref);
213-
stream.save_previous_value(cref);
213+
214214

215215
if (!previous.is_defined()) {
216216
// if the previous value is undefined – the value of the field is the
@@ -220,14 +220,16 @@ class copy_or_increment_operator_impl : public mfast::detail::codec_helper {
220220
// considered
221221
// absent and the state of the previous value is changed to empty.
222222
if (cref.is_initial_value()) {
223-
223+
stream.save_previous_value(cref);
224224
pmap.set_next_bit(false);
225225
return;
226226
}
227227
} else if (previous.is_empty()) {
228+
228229
// if the previous value is empty – the value of the field is empty.
229230
// If the field is optional the value is considered absent.
230231
if (cref.absent()) {
232+
stream.save_previous_value(cref);
231233
pmap.set_next_bit(false);
232234
return;
233235
} else if (!cref.optional()) {
@@ -239,10 +241,11 @@ class copy_or_increment_operator_impl : public mfast::detail::codec_helper {
239241
// has optional presence.
240242
}
241243
} else if (Operation()(cref, previous)) {
244+
stream.save_previous_value(cref);
242245
pmap.set_next_bit(false);
243246
return;
244-
}
245-
247+
}
248+
stream.save_previous_value(cref);
246249
pmap.set_next_bit(true);
247250
stream << cref;
248251
}

src/mfast/coder/encoder_v2/fast_encoder_core.h

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ struct MFAST_CODER_EXPORT fast_encoder_core : mfast::detail::codec_helper {
9090
template <typename T, typename TypeCategory>
9191
void encode_field(const T &ext_ref, constant_operator_tag, TypeCategory);
9292

93+
template <typename T>
94+
void encode_field(const T &ext_ref, copy_operator_tag, number_type_tag);
95+
9396
template <typename T, typename TypeCategory>
9497
void encode_field(const T &ext_ref, copy_operator_tag, TypeCategory);
9598

@@ -306,9 +309,9 @@ void fast_encoder_core::encode_field(const T &ext_ref, constant_operator_tag,
306309
strm_.save_previous_value(cref);
307310
}
308311

309-
template <typename T, typename TypeCategory>
312+
template <typename T>
310313
void fast_encoder_core::encode_field(const T &ext_ref, copy_operator_tag,
311-
TypeCategory) {
314+
number_type_tag) {
312315
encoder_presence_map &pmap = *current_;
313316
typename T::cref_type cref = ext_ref.get();
314317

@@ -349,6 +352,52 @@ void fast_encoder_core::encode_field(const T &ext_ref, copy_operator_tag,
349352
strm_ << ext_ref;
350353
}
351354

355+
template <typename T, typename TypeCategory>
356+
void fast_encoder_core::encode_field(const T &ext_ref, copy_operator_tag,
357+
TypeCategory) {
358+
encoder_presence_map &pmap = *current_;
359+
typename T::cref_type cref = ext_ref.get();
360+
361+
value_storage previous = previous_value_of(cref);
362+
363+
if (!previous.is_defined()) {
364+
// if the previous value is undefined – the value of the field is the
365+
// initial value
366+
// that also becomes the new previous value.
367+
// If the field has optional presence and no initial value, the field is
368+
// considered
369+
// absent and the state of the previous value is changed to empty.
370+
if (cref.is_initial_value()) {
371+
strm_.save_previous_value(cref);
372+
pmap.set_next_bit(false);
373+
return;
374+
}
375+
} else if (previous.is_empty()) {
376+
// if the previous value is empty – the value of the field is empty.
377+
// If the field is optional the value is considered absent.
378+
if (!ext_ref.present()) {
379+
strm_.save_previous_value(cref);
380+
pmap.set_next_bit(false);
381+
return;
382+
} else if (!ext_ref.optional()) {
383+
// It is a dynamic error [ERR D6] if the field is mandatory.
384+
BOOST_THROW_EXCEPTION(fast_dynamic_error("D6"));
385+
386+
// We need to handle this case because the previous value may have been
387+
// modified by another instruction with the same key and that intruction
388+
// has optional presence.
389+
}
390+
} else if (equivalent(cref, previous)) {
391+
strm_.save_previous_value(cref);
392+
pmap.set_next_bit(false);
393+
return;
394+
}
395+
396+
strm_.save_previous_value(cref);
397+
pmap.set_next_bit(true);
398+
strm_ << ext_ref;
399+
}
400+
352401
template <typename T, typename TypeCategory>
353402
void fast_encoder_core::encode_field(const T &ext_ref, increment_operator_tag,
354403
TypeCategory) {

tests/encoder_operator_test.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,8 +1034,44 @@ TEST_CASE("test the encoding of fast no operator for ascii string", "[operator_n
10341034
inst.destruct_value(storage, &alloc);
10351035
inst.destruct_value(inst.prev_value(), &alloc);
10361036
}
1037-
1038-
1037+
}
1038+
1039+
TEST_CASE("test the encoding of fast operator copy for ascii string", "[operator_copy_ascii_encode_test]")
1040+
{
1041+
debug_allocator alloc;
1042+
value_storage storage;
1043+
1044+
{ // testing Option assci field with copy operator
1045+
ascii_field_instruction inst(operator_copy,
1046+
presence_optional,
1047+
1,
1048+
"test_ascii", "",
1049+
nullptr,
1050+
string_value_storage());
1051+
1052+
inst.construct_value(storage, &alloc);
1053+
1054+
ascii_string_mref result(&alloc, &storage, &inst);
1055+
1056+
result.as("0");
1057+
REQUIRE(encode_mref("\xc0\xb0", result, CHANGE_PREVIOUS_VALUE));
1058+
result.as("1");
1059+
REQUIRE(encode_mref("\xc0\xb1", result, CHANGE_PREVIOUS_VALUE));
1060+
1061+
inst.prev_value().defined(false);
1062+
result.as("0");
1063+
REQUIRE(encode_ext_cref("\xc0\xb0",
1064+
ext_cref<ascii_string_cref, copy_operator_tag, optional_without_initial_value_tag>(result),
1065+
CHANGE_PREVIOUS_VALUE, &alloc));
1066+
result.as("1");
1067+
REQUIRE(encode_ext_cref("\xc0\xb1",
1068+
ext_cref<ascii_string_cref, copy_operator_tag, optional_without_initial_value_tag>(result),
1069+
CHANGE_PREVIOUS_VALUE, &alloc));
1070+
1071+
inst.destruct_value(storage, &alloc);
1072+
inst.destruct_value(inst.prev_value(), &alloc);
1073+
}
1074+
10391075
}
10401076
TEST_CASE("test the encoding of fast operator delta for ascii string","[operator_delta_ascii_encode_test]")
10411077
{
@@ -1205,7 +1241,7 @@ TEST_CASE("test the encoding of fast operator delta for ascii string","[operator
12051241
}
12061242
}
12071243

1208-
TEST_CASE("test the encoding of fast operator unicode string","[operator_delta_unicode_encode_test]")
1244+
TEST_CASE("test the encoding of fast operator delta for unicode string","[operator_delta_unicode_encode_test]")
12091245
{
12101246
debug_allocator alloc;
12111247
value_storage storage;

0 commit comments

Comments
 (0)