cereal icon indicating copy to clipboard operation
cereal copied to clipboard

Eliminate JSON entry for empty std::optional

Open lowsfer opened this issue 4 years ago • 13 comments

This change remove the entry in JSON if what is being serialized/deserialized is of type std::optional<T>, and the value is std::nullopt. When it's not std::nullopt, only the contained value (T) is saved, instead of a flag plus the value.

This is helpful when using JSON as web protocol. People would want to eliminate optional entries when they are empty. This improved human-readability of the JSON protocol and make it easier to interact with other languages.

lowsfer avatar Dec 19 '20 08:12 lowsfer

Seems this is exactly what is requested here: https://github.com/USCiLab/cereal/issues/459

lowsfer avatar Dec 19 '20 08:12 lowsfer

It might be a good idea to make this an option of JSONArchive instead of altering its default behavior?

WSoptics avatar Feb 15 '21 14:02 WSoptics

@WSoptics Changed it to an option and defaults to false. Also added unit tests.

lowsfer avatar Aug 15 '21 05:08 lowsfer

I like the change but can't merge :-)

One thing though however, it seems the option is only available for C++17, which seems not really necessary?

You should probably ping @AzothAmmo to potentially have it merged.

fiesh avatar Aug 16 '21 06:08 fiesh

@fiesh std::optional is only available since C++17. You mean keep the option but leave it with no effect?

@AzothAmmo Can we merge this feature?

lowsfer avatar Aug 22 '21 10:08 lowsfer

@fiesh std::optional is only available since C++17. You mean keep the option but leave it with no effect?

Sorry, I somehow thought std::optional was C++11 -- you're right of course!

fiesh avatar Aug 23 '21 06:08 fiesh

Would also love to have this behavior in cereal, @AzothAmmo :)

winding-lines avatar Dec 29 '21 22:12 winding-lines

It has been ~1.75 years. @AzothAmmo Do you have any concerns on this PR?

lowsfer avatar Sep 15 '22 05:09 lowsfer

This seems like a good change, and one that makes the output more intuitive and interoperable. Any reason for the delay in merging this in?

akalsi87 avatar Jan 21 '23 07:01 akalsi87

@lowsfer it seems this change can't support out-of-order json fileds.

yuziqii avatar Oct 20 '23 04:10 yuziqii

I made a few changes to support out-of-order JSON fields. It works fine in my case, but I don't know if there are any side effects.

here are my changes:

template <class T> inline  std::enable_if_t<IsOptional<T>::value>
CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
{
  if (ar.skippedNullopt())
  {
    // search node name
    if (ar.searchNodeName(t.name))
    {
      ar.setNextName( t.name );
      std::decay_t<decltype(*t.value)> val;
      ar( val );
      t.value = std::move(val);
    }
    else
    {
      t.value = std::nullopt;
    }
  }
  else
  {
    loadImpl(ar, t);
  }
}
const char* searchNodeName(const char* name) const
{
  auto currentIterator = itsIteratorStack.back();
  const auto len = std::strlen( name );
  for (const auto& it : currentIterator)
  {
    const auto currentName = it.name.GetString();
    if( ( std::strncmp( name, currentName, len ) == 0 ) &&
        ( std::strlen( currentName ) == len ) )
    {
    return currentName;
    }
  }
  return nullptr;
}
// Iterator support range for syntax
auto begin()
{
  return itsMemberItBegin;
}

auto end()
{
   return itsMemberItEnd;
}

yuziqii avatar Oct 27 '23 09:10 yuziqii

@yuziqii Would you like to create a commit including your changes? You can create an PR into my forked branch lowsfer:eliminate-empty-optional, then I merge it and your commit will be included in this PR.

lowsfer avatar Mar 31 '24 07:03 lowsfer

@lowsfer Sure, I'd be happy to submit a PR , and I've already done that. Let me know if there's any problems. here is the PR.

yuziqii avatar Apr 01 '24 02:04 yuziqii