Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions include/cereal/types/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,55 @@
#include "cereal/types/concepts/pair_associative_container.hpp"
#include <map>

namespace cereal
{
/**
* std::multimap must not default to the implementation in
* pair_associative_container.hpp, because it incorrectly
* handles equivalent keys when loading the map.
*
* The cause is the use of emplace_hint.
* Since it iserts the value before the hint, key order will be flipped
*
* Here we are using emplace (if key is equivalent to the previous one),
* or emplace_hint if keys are different, because this is a faster path
*
* Emplace will preserve order of equivalent keys, while where
* non-equivalent ones are placed doesn't matter.
**/

template <class Archive, typename... Args>
inline void load(Archive &ar, std::multimap<Args...> &map)
{
size_type size;
ar(make_size_tag(size));

map.clear();

typename std::multimap<Args...>::key_compare cmp;
auto hint = map.begin();
for (size_t i = 0; i < size; ++i)
{
typename std::multimap<Args...>::key_type key;
typename std::multimap<Args...>::mapped_type value;

ar(make_map_item(key, value));
if(!cmp(hint->first, key) && !cmp(key, hint->first)) {
#ifdef CEREAL_OLDER_GCC
hint = map.insert(std::move(key), std::move(value));
#else // NOT CEREAL_OLDER_GCC
hint = map.emplace(std::move(key), std::move(value));
#endif // NOT CEREAL_OLDER_GCC
} else {
#ifdef CEREAL_OLDER_GCC
hint = map.insert_hint(hint, std::move(key), std::move(value));
#else // NOT CEREAL_OLDER_GCC
hint = map.emplace_hint(hint, std::move(key), std::move(value));
#endif // NOT CEREAL_OLDER_GCC
}

}
}
}

#endif // CEREAL_TYPES_MAP_HPP_
29 changes: 28 additions & 1 deletion include/cereal/types/set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,34 @@ namespace cereal
template <class Archive, class K, class C, class A> inline
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> & multiset )
{
set_detail::load( ar, multiset );
size_type size;
ar( make_size_tag( size ) );

multiset.clear();

typename std::multiset<K, C, A>::key_compare cmp;

auto hint = multiset.begin();
for( size_type i = 0; i < size; ++i )
{
typename std::multiset<K, C, A>::key_type key;
ar( key );

// if hint == key
if(!cmp(*hint, key) && !cmp(key, *hint)) {
#ifdef CEREAL_OLDER_GCC
hint = multiset.insert(std::move(key));
#else // NOT CEREAL_OLDER_GCC
hint = multiset.emplace(std::move(key));
#endif // NOT CEREAL_OLDER_GCC
}else {
#ifdef CEREAL_OLDER_GCC
hint = multiset.insert_hint( hint, std::move( key ) );
#else // NOT CEREAL_OLDER_GCC
hint = multiset.emplace_hint( hint, std::move( key ) );
#endif // NOT CEREAL_OLDER_GCC
}
}
}
} // namespace cereal

Expand Down