Multilevel Deduplication Engine (MDE)
Loading...
Searching...
No Matches
mde.hpp
Go to the documentation of this file.
1
6#ifndef MDE_HPP
7#define MDE_HPP
8
9#include "mde_common.hpp"
10#include "profiling.hpp"
11
12#include <tuple>
13#include <utility>
14#include <algorithm>
15
16namespace mde {
17
25
26 std::string to_string() const {
27 std::stringstream s;
28 s << "(" << left << "," << right << ")";
29 return s.str();
30 }
31
32 bool operator<(const OperationNode &op) const {
33 return (left < op.left) || (right < op.right);
34 }
35
36 bool operator==(const OperationNode &op) const {
37 return (left == op.left) && (right == op.right);
38 }
39};
40
41inline std::ostream &operator<<(std::ostream &os, const OperationNode &op) {
42 return os << op.to_string();
43}
44
45} // END namespace mde
46
47/************************** START GLOBAL NAMESPACE ****************************/
48
49template <>
50struct std::hash<mde::OperationNode> {
52 return
53 std::hash<mde::IndexValue>()(k.left) ^
54 (std::hash<mde::IndexValue>()(k.right) << 1);
55 }
56};
57
58/************************** END GLOBAL NAMESPACE ******************************/
59
60namespace mde {
61
70template<typename OrderedSetT, typename ElementT, typename PropertyLess>
71struct SetLess {
72 bool operator()(const OrderedSetT *a, const OrderedSetT *b) const {
73 PropertyLess less;
74
75 auto cursor_1 = a->begin();
76 const auto &cursor_end_1 = a->end();
77 auto cursor_2 = b->begin();
78 const auto &cursor_end_2 = b->end();
79
80 while (cursor_1 != cursor_end_1 && cursor_2 != cursor_end_2) {
81 if (less(*cursor_1, *cursor_2)) {
82 return true;
83 }
84
85 if (less(*cursor_2, *cursor_1)) {
86 return false;
87 }
88
89 cursor_1++;
90 cursor_2++;
91 }
92
93 return a->size() < b->size();
94 }
95};
96
105template<
106 typename SetT,
107 typename ElementT,
108 typename ElementHash = DefaultHash<ElementT>>
109struct SetHash {
110 Size operator()(const SetT *k) const {
111 // Adapted from boost::hash_combine
112 size_t hash_value = 0;
113 for (const auto &value : *k) {
115 }
116
117 return hash_value;
118 }
119};
120
129template<
130 typename SetT,
131 typename ElementT,
132 typename PropertyEqual = DefaultEqual<ElementT>>
133struct SetEqual {
134 inline bool operator()(const SetT *a, const SetT *b) const {
135 PropertyEqual eq;
136 if (a->size() != b->size()) {
137 return false;
138 }
139
140 if (a->size() == 0) {
141 return true;
142 }
143
144 auto cursor_1 = a->begin();
145 const auto &cursor_end_1 = a->end();
146 auto cursor_2 = b->begin();
147
148 while (cursor_1 != cursor_end_1) {
149 if (!eq(*cursor_1, *cursor_2)) {
150 return false;
151 }
152
153 cursor_1++;
154 cursor_2++;
155 }
156
157 return true;
158 }
159};
160
161#ifdef MDE_ENABLE_TBB
162
172template<typename T, typename Hash, typename Equal>
173struct TBBHashCompare {
174 Size hash(const T v) const {
175 return Hash()(v);
176 }
177
178 bool equal(const T a, const T b) const {
179 return Equal()(a, b);
180 }
181};
182
183#endif
184
185
189struct AssertError : public std::invalid_argument {
190 AssertError(const std::string &message):
191 std::invalid_argument(message.c_str()) {}
192};
193
197struct Unreachable : public std::runtime_error {
198 Unreachable(const std::string &message = "Hit a branch marked as unreachable."):
199 std::runtime_error(message.c_str()) {}
200};
201
202#define __MDE_EXCEPT(__msg) AssertError(__msg " [At: " __FILE__ ":" __MDE_STR(__LINE__) "]")
203
204#ifdef MDE_DEBUG
205#define __MDE_ASSERT(__cond, __msg_arg) \
206 { if (!(__cond)) { __MDE_EXCEPT(__msg_arg); } }
207#else
208#define __MDE_ASSERT(__cond, __msg_arg)
209#endif
210
211
218template<typename PropertySetT, typename PropertyElementT>
219static inline void verify_property_set_integrity(const PropertySetT &cont) {
220 if (cont.size() == 1) {
221 return;
222 }
223
224 std::unordered_set<
226 typename PropertyElementT::Hash> k;
227 const PropertyElementT *prev_val = nullptr;
228
229 for (const PropertyElementT &val : cont) {
230 if (prev_val && !(*prev_val < val)) {
231 throw AssertError("Supplied property set is not sorted.");
232 }
233
234 if (k.count(val) > 0) {
235 throw AssertError("Found duplicate key in given container.");
236 } else {
237 k.insert(val);
238 }
239
240 prev_val = &val;
241 }
242}
243
250#ifndef MDE_DISABLE_INTEGRITY_CHECKS
251#define MDE_PROPERTY_SET_INTEGRITY_VALID(__set) \
252 verify_property_set_integrity<PropertySet, PropertyElement>(__set);
253#else
254#define MDE_PROPERTY_SET_INTEGRITY_VALID(__set)
255#endif
256
257
274#ifdef MDE_ENABLE_DEBUG
275
278#define MDE_PROPERTY_SET_INDEX_VALID(__index) { \
279 _Pragma("GCC diagnostic push"); \
280 _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
281 if ((__index.value) < 0 || ((__index.value) > property_sets.size() - 1)) { \
282 throw __MDE_EXCEPT("Invalid index supplied"); \
283 } \
284 _Pragma("GCC diagnostic pop") \
285}
286
288#define MDE_PROPERTY_SET_PAIR_VALID(__index1, __index2) \
289 MDE_PROPERTY_SET_INDEX_VALID(__index1); \
290 MDE_PROPERTY_SET_INDEX_VALID(__index2);
291
293#define MDE_PROPERTY_SET_PAIR_UNEQUAL(__index1, __index2) \
294 if ((__index1) == (__index2)) { \
295 throw __MDE_EXCEPT("Equal set condition not handled by caller"); \
296 }
297
298#else
299
300#define MDE_PROPERTY_SET_INDEX_VALID(__index)
301#define MDE_PROPERTY_SET_PAIR_VALID(__index1, __index2)
302#define MDE_PROPERTY_SET_PAIR_UNEQUAL(__index1, __index2)
303
304#endif
305
306#if defined(MDE_ENABLE_PARALLEL) && !defined(MDE_ENABLE_TBB)
307#define MDE_PARALLEL(__x) __x
308#else
309#define MDE_PARALLEL(__x)
310#endif
311
312#ifdef MDE_ENABLE_EVICTION
313#define MDE_EVICTION(__x) __x
314#else
315#define MDE_EVICTION(__x)
316#endif
317
327#define MDE_PUSH_ONE(__cont, __val) (__cont).push_back((__val))
328
339#define MDE_PUSH_RANGE(__cont, __start, __end) (__cont).insert((__cont).end(), (__start), (__end))
340
341
349#define MDE_REGISTER_SET_INTERNAL(__set, __cold) register_set<MDE_DISABLE_INTERNAL_INTEGRITY_CHECK>((__set), (__cold))
350
357template<typename PropertyT>
360 static constexpr bool is_nested = false;
361
363 static constexpr Size num_children = 0;
364
365
367 using MDEReferenceList = std::tuple<>;
368
370 using ChildValueList = std::tuple<>;
371
381 template<
382 typename PropertyLess,
383 typename PropertyHash,
384 typename PropertyEqual,
385 typename PropertyPrinter>
387 public:
389 using InterfaceKeyType = PropertyT;
390
392 using InterfaceValueType = PropertyT;
393
394 protected:
395 PropertyT value;
396
397 public:
398 PropertyElement(const PropertyT &value): value(value) {}
399
405 const PropertyT &get_key() const {
406 return value;
407 }
408
415 const PropertyT &get_value() const {
416 return value;
417 }
418
426 return *this;
427 }
428
429 bool operator<(const PropertyElement &b) const {
430 return PropertyLess()(value, b.value);
431 }
432
433 bool operator==(const PropertyElement &b) const {
434 return PropertyEqual()(value, b.value);
435 }
436
438 return PropertyPrinter()(value);
439 }
440
441 friend std::ostream& operator<<(std::ostream& os, const PropertyElement& obj) {
442 os << obj.to_string();
443 return os;
444 }
445
446 struct Hash {
448 return PropertyHash()(p.value);
449 }
450 };
451
461 struct FullEqual {
462 bool operator()(const PropertyElement &a, const PropertyElement &b) const {
463 return PropertyEqual()(a.value, b.value);
464 }
465 };
466 };
467
468};
469
470
481#define MDE_BINARY_NESTED_OPERATION(__op_name) \
482 struct __NestingOperation_ ## __op_name { \
483 template<typename ArgIndex, typename MDE> \
484 void operator()(ArgIndex &ret, MDE &mde, const ArgIndex &c, const ArgIndex &d) { \
485 ret = mde . __op_name (c, d); \
486 } \
487 };
488
500#define MDE_PERFORM_BINARY_NESTED_OPERATION(__op_name, __reflist, __arg1, __arg2) \
501 ((__arg1) . template apply<__NestingOperation_ ## __op_name>((__reflist), (__arg2)))
502
510template<typename PropertyT, typename ...ChildT>
513 static constexpr bool is_nested = true;
514
517 static constexpr Size num_children = sizeof...(ChildT);
518
520 using MDEReferenceList = std::tuple<ChildT&...>;
521
524 using ChildValueList = std::tuple<typename ChildT::Index...>;
525
527 template<std::size_t ListIndex>
529 typename std::tuple_element<ListIndex, ChildValueList>::type;
530
540 template<
541 typename PropertyLess,
542 typename PropertyHash,
543 typename PropertyEqual,
544 typename PropertyPrinter>
546 public:
548 using InterfaceKeyType = PropertyT;
549
551 using InterfaceValueType = PropertyT;
552
553 private:
554 PropertyT _key;
555 ChildValueList _value;
556
557 public:
559 const PropertyT &key,
560 const ChildValueList &value):
561 _key(key),
562 _value(value) {}
563
569 const PropertyT &get_key() const {
570 return _key;
571 }
572
578 const PropertyT &key() const {
579 return _key;
580 }
581
589 const ChildValueList &get_value() const {
590 return _value;
591 }
592
598 template<int ListIndex>
600 return std::get<ListIndex>(_value);
601 }
602
604 return std::get<0>(_value);
605 }
606
623 template <typename Operation, Size... Indices>
626 const MDEReferenceList &mde,
628 std::index_sequence<Indices...>) const {
629 ((Operation()(std::get<Indices>(ret),
630 std::get<Indices>(mde),
631 std::get<Indices>(_value),
632 std::get<Indices>(arg_value)
633 )), ...);
634 }
635
648 template<typename Operation>
650 const MDEReferenceList &mde,
651 const PropertyElement &arg) const {
654 ret,
655 mde,
656 arg._value,
657 std::make_index_sequence<num_children>{});
658 return PropertyElement(_key, ret);
659 }
660
661 bool operator<(const PropertyElement &b) const {
662 return PropertyLess()(_key, b._key);
663 }
664
665 bool operator==(const PropertyElement &b) const {
666 return PropertyEqual()(_key, b._key);
667 }
668
670 std::stringstream s;
671 s << PropertyPrinter()(_key);
672 s << " -> [ ";
673 std::apply(
674 [&s](auto&&... args) {
675 ((s << args.value << ' '), ...);
676 }, _value);
677 s << "]";
678 return s.str();
679 }
680
681 friend std::ostream& operator<<(std::ostream& os, const PropertyElement& obj) {
682 os << obj.to_string();
683 return os;
684 }
685
686 struct Hash {
688 return PropertyHash()(p._key);
689 }
690 };
691
698 struct FullEqual {
699 bool operator()(const PropertyElement &a, const PropertyElement &b) const {
700 return PropertyEqual()(a._key, b._key) && (a._value == b._value);
701 }
702 };
703 };
704};
705
706
716#ifdef MDE_ENABLE_TBB
717
718template<typename MapClass>
719class MapAdapter {
720public:
721 using Map = MapClass;
722 using Key = typename Map::key_type;
723 using MappedType = typename Map::mapped_type;
724 using KeyValuePair = typename Map::value_type;
725
726protected:
727 using Accessor = typename Map::const_accessor;
728 Map data;
729
730public:
731 Optional<MappedType> find(const Key &key) const {
733 bool found = data.find(acc, key);
734 if (!found) {
736 } else {
737 return acc->second;
738 }
739 }
740
741 void insert(KeyValuePair &&v) {
742 data.insert(std::move(v));
743 }
744
745 void clear() {
746 data.clear();
747 }
748
749 Size size() const {
750 return data.size();
751 }
752
753 typename Map::const_iterator begin() const {
754 return data.begin();
755 }
756
757 typename Map::const_iterator end() const {
758 return data.end();
759 }
760
761 String to_string() const {
762 std::stringstream s;
763
764 for (auto i : data) {
765 s << " {" << i.first << " -> " << i.second << "} \n";
766 }
767
768 return s.str();
769 }
770
771};
772
773#else
774
775template<typename MapClass>
777public:
778 using Map = MapClass;
779 using Key = typename Map::key_type;
780 using MappedType = typename Map::mapped_type;
781 using KeyValuePair = typename Map::value_type;
782
783protected:
785 MDE_PARALLEL(mutable RWMutex mutex;)
786
787public:
789 MDE_PARALLEL(ReadLock m(mutex);)
790 auto value = data.find(key);
791 if (value == data.end()) {
793 } else {
794 return value->second;
795 }
796 }
797
799 MDE_PARALLEL(WriteLock m(mutex);)
800 data.insert(std::move(v));
801 }
802
803 void clear() {
804 MDE_PARALLEL(WriteLock m(mutex);)
805 data.clear();
806 }
807
808 Size size() const {
809 MDE_PARALLEL(ReadLock m(mutex);)
810 return data.size();
811 }
812
813 typename Map::const_iterator begin() const {
814 return data.begin();
815 }
816
817 typename Map::const_iterator end() const {
818 return data.end();
819 }
820
822 MDE_PARALLEL(ReadLock m(mutex);)
823 std::stringstream s;
824
825 for (auto i : data) {
826 s << " {" << i.first << " -> " << i.second << "} \n";
827 }
828
829 return s.str();
830 }
831
832};
833
834#endif
835
836
842#ifdef MDE_ENABLE_TBB
843
844template<typename K, typename V>
845using InternalMap = MapAdapter<tbb::concurrent_hash_map<K, V>>;
846
847#else
848
849template<typename K, typename V>
851
852#endif
853
858template<typename T>
860
866 size_t hits = 0;
867
869 size_t equal_hits = 0;
870
873 size_t subset_hits = 0;
874
877 size_t empty_hits = 0;
878
881 size_t cold_misses = 0;
882
885 size_t edge_misses = 0;
886
888 std::stringstream s;
889 s << " " << "Hits : " << hits << "\n"
890 << " " << "Equal Hits : " << equal_hits << "\n"
891 << " " << "Subset Hits: " << subset_hits << "\n"
892 << " " << "Empty Hits : " << empty_hits << "\n"
893 << " " << "Cold Misses: " << cold_misses << "\n"
894 << " " << "Edge Misses: " << edge_misses << "\n";
895 return s.str();
896 }
897};
898
909#ifdef MDE_ENABLE_PERFORMANCE_METRICS
910#define MDE_PERF_INC(__oper, __category) (perf[__MDE_STR(__oper)] . __category ++)
911#else
912#define MDE_PERF_INC(__oper, __category)
913#endif
914
915template <typename T>
916struct MDEConfig {
917 static constexpr const char* name = "";
918
919 using PropertyT = T;
924
925 static constexpr Size BLOCK_SHIFT = MDE_DEFAULT_BLOCK_SHIFT;
926 static constexpr Size BLOCK_SIZE = MDE_DEFAULT_BLOCK_SIZE;
927 static constexpr Size BLOCK_MASK = MDE_DEFAULT_BLOCK_MASK;
928};
929
948template <
949 typename Config,
951class MDENode {
952public:
953 using PropertyT = typename Config::PropertyT;
954 using PropertyLess = typename Config::PropertyLess;
955 using PropertyHash = typename Config::PropertyHash;
956 using PropertyEqual = typename Config::PropertyEqual;
957 using PropertyPrinter = typename Config::PropertyPrinter;
959
960 static constexpr const char *name = Config::name;
961 static constexpr Size BLOCK_SIZE = Config::BLOCK_SIZE;
962 static constexpr Size BLOCK_MASK = Config::BLOCK_MASK;
963 static constexpr Size BLOCK_SHIFT = Config::BLOCK_SHIFT;
964
969 struct Index {
971
972 Index(IndexValue idx = EMPTY_SET_VALUE): value(idx) {}
973
974 bool is_empty() const {
975 return value == EMPTY_SET_VALUE;
976 }
977
978 bool operator==(const Index &b) const {
979 return value == b.value;
980 }
981
982 bool operator!=(const Index &b) const {
983 return value != b.value;
984 }
985
986 bool operator<(const Index &b) const {
987 return value < b.value;
988 }
989
990 bool operator>(const Index &b) const {
991 return value > b.value;
992 }
993
995 return std::to_string(value);
996 }
997
998 friend std::ostream& operator<<(std::ostream& os, const Index& obj) {
999 os << obj.to_string();
1000 return os;
1001 }
1002
1003 struct Hash {
1004 Size operator()(const Index &idx) const {
1005 return DefaultHash<IndexValue>()(idx.value);
1006 }
1007 };
1008 };
1009
1015 typename Nesting::template PropertyElement<
1020
1025 using PropertySet = std::vector<PropertyElement>;
1026
1028 SetHash<
1031 typename PropertyElement::Hash>;
1032
1034 SetEqual<
1037 typename PropertyElement::FullEqual>;
1038
1062#ifdef MDE_ENABLE_TBB
1063 using PropertySetMap =
1064 MapAdapter<tbb::concurrent_hash_map<
1065 const PropertySet *, IndexValue,
1067 const PropertySet *,
1070#else
1072 MapAdapter<std::unordered_map<
1073 const PropertySet *, IndexValue,
1076#endif
1077
1080 using RefList = typename Nesting::MDEReferenceList;
1081
1082protected:
1084
1085#ifdef MDE_ENABLE_PERFORMANCE_METRICS
1088#endif
1089
1092 using Ptr = typename PtrContainer::pointer;
1093
1095
1097
1098 Ptr get() const {
1099 return ptr.get();
1100 }
1101
1102 bool is_evicted() const {
1103#ifdef MDE_ENABLE_EVICTION
1104 return ptr.get() == nullptr;
1105#else
1106 return false;
1107#endif
1108 }
1109
1110#ifdef MDE_ENABLE_EVICTION
1111
1112 void evict() {
1113 __MDE_ASSERT(is_present(),
1114 "Tried to evict an already absent property set")
1115 ptr.release();
1116 }
1117
1118 void reassign(Ptr &&p) {
1119 __MDE_ASSERT(!is_present(),
1120 "Tried to reassign when a property set is already present");
1121 ptr.reset(p);
1122 }
1123
1124 void swap(PropertySetHolder &p) {
1125 __MDE_ASSERT(!is_present(),
1126 "Tried to reassign when a property set is already present");
1127 __MDE_ASSERT(p.is_present(),
1128 "Attempted to swap to a null pointer");
1129 ptr.swap(p.ptr);
1130 }
1131
1132#endif
1133 };
1134
1135#if defined(MDE_ENABLE_TBB)
1136
1137 class PropertySetStorage {
1138 protected:
1141 // is important for eviction to work.
1142 mutable tbb::concurrent_vector<PropertySetHolder> data = {};
1143
1144 public:
1154 PropertySetHolder &at_mutable(const Index &idx) const {
1155 return data.at(idx.value);
1156 }
1157
1158 const PropertySetHolder &at(const Index &idx) const {
1159 return data.at(idx.value);
1160 }
1161
1162 Index push_back(PropertySetHolder &&p) {
1163 auto it = data.push_back(std::move(p));
1164 return it - data.begin();
1165 }
1166
1167 void clear() {
1168 data.clear();
1169 }
1170
1171 Size size() const {
1172 return data.size();
1173 }
1174
1175
1176 };
1177
1178#elif defined(MDE_ENABLE_PARALLEL)
1179
1180 class PropertySetStorage {
1181 protected:
1184 // is important for eviction to work.
1185 mutable Vector<Vector<PropertySetHolder>> data = {};
1186
1187 mutable RWMutex mutex;
1188 mutable RWMutex realloc_mutex;
1189
1190 std::atomic<Size> total_elems = 0;
1191 std::atomic<Size> block_base = 0;
1192
1193 public:
1194 PropertySetStorage() {
1195 data.push_back({});
1196 data.back().reserve(BLOCK_SIZE);
1197 }
1198
1208 PropertySetHolder &at_mutable(const Index &idx) const {
1209 ReadLock m(realloc_mutex);
1210 if (idx.value >= block_base) {
1211 return data.back().at(idx.value & BLOCK_MASK);
1212 } else {
1213 return
1214 data
1215 .at((idx.value & (~BLOCK_MASK)) >> BLOCK_SHIFT)
1216 .at(idx.value & BLOCK_MASK);
1217 }
1218 }
1219
1220 const PropertySetHolder &at(const Index &idx) const {
1221 ReadLock m(realloc_mutex);
1222 if (idx.value >= block_base) {
1223 return data.back().at(idx.value & BLOCK_MASK);
1224 } else {
1225 return
1226 data
1227 .at((idx.value & (~BLOCK_MASK)) >> BLOCK_SHIFT)
1228 .at(idx.value & BLOCK_MASK);
1229 }
1230 }
1231
1232 Index push_back(PropertySetHolder &&p) {
1233 WriteLock m(mutex);
1234 __MDE_ASSERT(!data.empty(), "Internal error: no storage blocks avaialable.");
1235 if (data.back().size() >= BLOCK_SIZE) {
1236 WriteLock r(realloc_mutex);
1237 data.push_back({});
1238 data.back().reserve(BLOCK_SIZE);
1239 block_base += BLOCK_SIZE;
1240 }
1241 data.back().push_back(std::move(p));
1242 total_elems++;
1243 return Index(total_elems - 1);
1244 }
1245
1246 void clear() {
1247 WriteLock m(mutex);
1248 data.clear();
1249 data.push_back({});
1250 total_elems = 0;
1251 block_base = 0;
1252 }
1253
1254 Size size() const {
1255 return total_elems;
1256 }
1257 };
1258
1259#else
1260
1262 protected:
1265 // is important for eviction to work.
1266 mutable Vector<PropertySetHolder> data = {};
1267
1268 public:
1279 return data.at(idx.value);
1280 }
1281
1282 const PropertySetHolder &at(const Index &idx) const {
1283 return data.at(idx.value);
1284 }
1285
1287 data.push_back(std::move(p));
1288 return data.size() - 1;
1289 }
1290
1291 void clear() {
1292 data.clear();
1293 }
1294
1295 Size size() const {
1296 return data.size();
1297 }
1298 };
1299
1300#endif
1301
1302 // The property set storage array.
1303 PropertySetStorage property_sets = {};
1304
1305 // The property set -> Index in storage array mapping.
1306 PropertySetMap property_set_map = {};
1307
1309 BinaryOperationMap intersections = {};
1310 BinaryOperationMap differences = {};
1311
1313
1321 void store_subset(const Index &a, const Index &b) {
1324 __mde_calc_functime(stat);
1325
1326 // We need to maintain the operation pair in index-order here as well.
1327 if (a > b) {
1328 subsets.insert({{b.value, a.value}, SUPERSET});
1329 } else {
1330 subsets.insert({{a.value, b.value}, SUBSET});
1331 }
1332 }
1333
1337 virtual void clear() {
1338 property_sets.clear();
1339 property_set_map.clear();
1340 unions.clear();
1341 intersections.clear();
1342 differences.clear();
1343 subsets.clear();
1344 }
1345
1346public:
1347 explicit MDENode(RefList reflist = {}): reflist(reflist) {
1348 // INSERT EMPTY SET AT INDEX 0
1349 register_set({ });
1350 }
1351
1352 inline bool is_empty(const Index &i) const {
1353 return i.is_empty();
1354 }
1355
1360 clear();
1361 register_set({ });
1362 }
1363
1373 SubsetRelation is_subset(const Index &a, const Index &b) const {
1375
1376 auto i = subsets.find({a.value, b.value});
1377
1378 if (!i.is_present()) {
1379 return UNKNOWN;
1380 } else {
1381 return i.get();
1382 }
1383 }
1384
1396 __mde_calc_functime(stat);
1397
1399
1400 auto result = property_set_map.find(new_set.get());
1401
1402 if (!result.is_present()) {
1403 MDE_PERF_INC(property_sets, cold_misses);
1404
1405 Index ret = property_sets.push_back(std::move(new_set));
1406 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1407
1408 return ret;
1409 }
1410 MDE_EVICTION(else if (is_evicted(result.get())) {
1411 property_sets.at_mutable(result.get()).swap(new_set);
1412 return Index(result.get());
1413 })
1414 else {
1415 MDE_PERF_INC(property_sets, hits);
1416 return Index(result.get());
1417 }
1418 }
1419
1431 __mde_calc_functime(stat);
1432
1434 auto result = property_set_map.find(new_set.get());
1435
1436 if (!result.is_present()) {
1437 MDE_PERF_INC(property_sets, cold_misses);
1438
1439 Index ret = property_sets.push_back(std::move(new_set));
1440 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1441
1442 cold = true;
1443 return ret;
1444 }
1445 MDE_EVICTION(else if (is_evicted(result.get())) {
1446 property_sets.at_mutable(result.get()).swap(new_set);
1447 cold = false;
1448 return Index(result.get());
1449 })
1450 else {
1451 MDE_PERF_INC(property_sets, hits);
1452 cold = false;
1453 return Index(result.get());
1454 }
1455 }
1456
1466 std::unordered_set<
1468 typename PropertyElement::Hash,
1469 typename PropertyElement::FullEqual> deduplicator;
1470
1471 for (auto &i : c) {
1472 deduplicator.insert(i);
1473 }
1474
1475 c.assign(deduplicator.begin(), deduplicator.end());
1476 std::sort(c.begin(), c.end());
1477 }
1478
1479 template <bool disable_integrity_check = false>
1481 __mde_calc_functime(stat);
1482
1485 }
1486
1487 auto result = property_set_map.find(&c);
1488
1489 if (!result.is_present()) {
1490 MDE_PERF_INC(property_sets, cold_misses);
1491
1493 Index ret = property_sets.push_back(std::move(new_set));
1494 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1495 return ret;
1496 }
1497 MDE_EVICTION(else if (is_evicted(result.get())) {
1498 property_sets.at_mutable(result.get()).reassign(new PropertySet(c));
1499 return Index(result.get());
1500 })
1501 else {
1502 MDE_PERF_INC(property_sets, hits);
1503 return Index(result.get());
1504 }
1505 }
1506
1507 template <bool disable_integrity_check = false>
1509 __mde_calc_functime(stat);
1510
1513 }
1514
1515 auto result = property_set_map.find(&c);
1516
1517 if (!result.is_present()) {
1518 MDE_PERF_INC(property_sets, cold_misses);
1519
1521 Index ret = property_sets.push_back(std::move(new_set));
1522 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1523
1524 cold = true;
1525 return ret;
1526 }
1527 MDE_EVICTION(else if (is_evicted(result.get())) {
1528 property_sets.at_mutable(result.get()).reassign(new PropertySet(c));
1529 cold = false;
1530 return Index(result.get());
1531 })
1532 else {
1533 MDE_PERF_INC(property_sets, hits);
1534 cold = false;
1535 return Index(result.get());
1536 }
1537 }
1538
1539 template <bool disable_integrity_check = false>
1541 __mde_calc_functime(stat);
1542
1545 }
1546
1547 auto result = property_set_map.find(&c);
1548
1549 if (!result.is_present()) {
1550 MDE_PERF_INC(property_sets, cold_misses);
1551
1552 PropertySetHolder new_set(new PropertySet(std::move(c)));
1553 Index ret = property_sets.push_back(std::move(new_set));
1554 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1555 return ret;
1556 }
1557 MDE_EVICTION(else if (is_evicted(result.get())) {
1558 property_sets.at_mutable(result.get()).reassign(new PropertySet(c));
1559 return Index(result.get());
1560 })
1561 else {
1562 MDE_PERF_INC(property_sets, hits);
1563 return Index(result.get());
1564 }
1565 }
1566
1567 template <bool disable_integrity_check = false>
1569 __mde_calc_functime(stat);
1570
1573 }
1574
1575 auto result = property_set_map.find(&c);
1576
1577 if (!result.is_present()) {
1578 MDE_PERF_INC(property_sets, cold_misses);
1579
1580 PropertySetHolder new_set(new PropertySet(std::move(c)));
1581 Index ret = property_sets.push_back(std::move(new_set));
1582 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1583
1584 cold = true;
1585 return ret;
1586 }
1587 MDE_EVICTION(else if (is_evicted(result.get())) {
1588 property_sets.at_mutable(result.get()).reassign(new PropertySet(c));
1589 cold = false;
1590 return Index(result.get());
1591 })
1592 else {
1593 MDE_PERF_INC(property_sets, hits);
1594 cold = false;
1595 return Index(result.get());
1596 }
1597 }
1598
1599 template<typename Iterator, bool disable_integrity_check = false>
1601 __mde_calc_functime(stat);
1602
1603 PropertySetHolder new_set(new PropertySet(begin, end));
1604
1607 }
1608
1609 auto result = property_set_map.find(new_set.get());
1610
1611 if (!result.is_present()) {
1612 MDE_PERF_INC(property_sets, cold_misses);
1613
1614 Index ret = property_sets.push_back(std::move(new_set));
1615 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1616 return ret;
1617 }
1618 MDE_EVICTION(else if (is_evicted(result.get())) {
1619 property_sets.at_mutable(result.get()).reassign(std::move(new_set));
1620 return Index(result.get());
1621 })
1622 else {
1623 MDE_PERF_INC(property_sets, hits);
1624 return Index(result.get());
1625 }
1626 }
1627
1628 template<typename Iterator, bool disable_integrity_check = false>
1630 __mde_calc_functime(stat);
1631
1632 PropertySetHolder new_set(new PropertySet(begin, end));
1633
1636 }
1637
1638 auto result = property_set_map.find(new_set.get());
1639
1640 if (!result.is_present()) {
1641 MDE_PERF_INC(property_sets, cold_misses);
1642
1643 Index ret = property_sets.push_back(std::move(new_set));
1644 property_set_map.insert(std::make_pair(property_sets.at(ret).get(), ret.value));
1645 cold = true;
1646 return ret;
1647 }
1648 MDE_EVICTION(else if (is_evicted(result.get())) {
1649 property_sets.at_mutable(result.get()).reassign(std::move(new_set));
1650 cold = false;
1651 return Index(result.get());
1652 })
1653 else {
1654 MDE_PERF_INC(property_sets, hits);
1655 cold = false;
1656 return Index(result.get());
1657 }
1658 }
1659
1660#ifdef MDE_ENABLE_EVICTION
1661 bool is_evicted(const Index &index) const {
1662 return property_sets.at(index.value).is_evicted();
1663 }
1664#endif
1665
1666#ifdef MDE_ENABLE_EVICTION
1667 void evict_set(const Index &index) {
1668 __MDE_ASSERT(!index.is_empty(),
1669 "Tried to evict the empty set");
1670 property_sets.at_mutable(index.value).evict();
1671 }
1672#endif
1673
1681 inline const PropertySet &get_value(const Index &index) const {
1683#if defined(MDE_DEBUG) && defined(MDE_ENABLE_EVICTION)
1684 __MDE_ASSERT(!is_evicted(index),
1685 "Tried to access an evicted set");
1686#endif
1687 return *property_sets.at(index.value).get();
1688 }
1689
1696 inline Size property_set_count() const {
1697 return property_sets.size();
1698 }
1699
1707 inline Size size_of(const Index &index) const {
1708 if (index == EMPTY_SET_VALUE) {
1709 return 0;
1710 } else {
1711 return get_value(index).size();
1712 }
1713 }
1714
1724 static inline bool less(const PropertyElement &a, const PropertyElement &b) {
1725 return a < b;
1726 }
1727
1728 static inline bool less_key(const PropertyElement &a, const PropertyT &b) {
1729 return PropertyLess()(a.get_key(), b);
1730 }
1731
1732 static inline bool less_key(const PropertyElement &a, const PropertyElement &b) {
1733 return PropertyLess()(a.get_key(), b.get_key());
1734 }
1735
1745 static inline bool equal(const PropertyElement &a, const PropertyElement &b) {
1746 return a == b;
1747 }
1748
1749 static inline bool equal_key(const PropertyElement &a, const PropertyT &b) {
1750 return PropertyEqual()(a.get_key(), b);
1751 }
1752
1753 static inline bool equal_key(const PropertyElement &a, const PropertyElement &b) {
1754 return PropertyEqual()(a.get_key(), b.get_key());
1755 }
1756
1767 inline OptionalRef<PropertyElement> find_key(const Index &index, const PropertyT &p) const {
1768 if (is_empty(index)) {
1770 }
1771
1772 const PropertySet &s = get_value(index);
1773
1775 for (const PropertyElement &i : s) {
1776 if (equal_key(i, p)) {
1778 }
1779 }
1780 } else {
1781 // Binary search implementation
1782 long int low = 0;
1783 long int high = s.size() - 1;
1784
1785 while (low <= high) {
1786 long int mid = low + (high - low) / 2;
1787
1788 if (equal_key(s[mid], p)) {
1790 } else if (less_key(s[mid], p)) {
1791 low = mid + 1;
1792 } else {
1793 high = mid - 1;
1794 }
1795 }
1796 }
1797
1799 }
1800
1810 inline bool contains(const Index &index, const PropertyElement &prop) const {
1811 if (is_empty(index)) {
1812 return false;
1813 }
1814
1815 const PropertySet &s = get_value(index);
1816
1818 for (PropertyElement i : s) {
1819 if (equal_key(i, prop)) {
1820 return true;
1821 }
1822 }
1823 } else {
1824 // Binary search implementation
1825 std::int64_t low = 0;
1826 std::int64_t high = s.size() - 1;
1827
1828 while (low <= high) {
1829 long int mid = low + (high - low) / 2;
1830 if (equal_key(s[mid], prop)) {
1831 return true;
1832 } else if (less_key(s[mid], prop)) {
1833 low = mid + 1;
1834 } else {
1835 high = mid - 1;
1836 }
1837 }
1838 }
1839
1840 return false;
1841 }
1842
1853 Index set_union(const Index &_a, const Index &_b) {
1855 __mde_calc_functime(stat);
1856
1857 if (_a == _b) {
1858 MDE_PERF_INC(unions, equal_hits);
1859 return Index(_a);
1860 }
1861
1862 if (is_empty(_a)) {
1863 MDE_PERF_INC(unions, empty_hits);
1864 return Index(_b);
1865 } else if (is_empty(_b)) {
1866 MDE_PERF_INC(unions,empty_hits);
1867 return Index(_a);
1868 }
1869
1870 const Index &a = std::min(_a, _b);
1871 const Index &b = std::max(_a, _b);
1872
1873 SubsetRelation r = is_subset(a, b);
1874
1875 if (r == SUBSET) {
1876 MDE_PERF_INC(unions, subset_hits);
1877 return Index(b);
1878 } else if (r == SUPERSET) {
1879 MDE_PERF_INC(unions, subset_hits);
1880 return Index(a);
1881 }
1882
1883 auto result = unions.find({a.value, b.value});
1884
1885 if (!result.is_present() MDE_EVICTION(|| is_evicted(result.get()))) {
1887 const PropertySet &first = get_value(a);
1888 const PropertySet &second = get_value(b);
1889
1890 // The union implementation here is adapted from the example
1891 // suggested implementation provided of std::set_union from
1892 // cppreference.com
1893 auto cursor_1 = first.begin();
1894 const auto &cursor_end_1 = first.end();
1895 auto cursor_2 = second.begin();
1896 const auto &cursor_end_2 = second.end();
1897
1898 while (cursor_1 != cursor_end_1) {
1899 if (cursor_2 == cursor_end_2) {
1901 break;
1902 }
1903
1904 if (less(*cursor_2, *cursor_1)) {
1906 cursor_2++;
1907 } else {
1908 if (!(less(*cursor_1, *cursor_2))) {
1909 if constexpr (Nesting::is_nested) {
1912 set_union, reflist, *cursor_1, *cursor_2);
1914 } else {
1916 }
1917 cursor_2++;
1918 } else {
1920 }
1921 cursor_1++;
1922 }
1923 }
1924
1926
1927 bool cold = false;
1928 Index ret;
1929
1930 MDE_EVICTION(if (result.is_present() && is_evicted(result.get())) {
1931 ret = result.get();
1932 property_sets.at_mutable(ret).reassign(new PropertySet(std::move(new_set)));
1933 } else) {
1935
1936 unions.insert({{a.value, b.value}, ret.value});
1937
1938 if (ret == a) {
1939 store_subset(b, ret);
1940 } else if (ret == b) {
1941 store_subset(a, ret);
1942 } else {
1943 store_subset(a, ret);
1944 store_subset(b, ret);
1945 }
1946 }
1947
1948 if (cold) {
1949 MDE_PERF_INC(unions, cold_misses);
1950 } else {
1951 MDE_PERF_INC(unions, edge_misses);
1952 }
1953
1954 return Index(ret);
1955 } else {
1956 MDE_PERF_INC(unions, hits);
1957 return Index(result.get());
1958 }
1959 }
1960
1972 return set_union(a, register_set_single(b));
1973 }
1974
1984 MDE_BINARY_NESTED_OPERATION(set_difference)
1985 Index set_difference(const Index &a, const Index &b) {
1987 __mde_calc_functime(stat);
1988
1989 if (a == b) {
1990 MDE_PERF_INC(differences, equal_hits);
1991 return Index(EMPTY_SET_VALUE);
1992 }
1993
1994 if (is_empty(a)) {
1995 MDE_PERF_INC(differences, empty_hits);
1996 return Index(EMPTY_SET_VALUE);
1997 } else if (is_empty(b)) {
1998 MDE_PERF_INC(differences, empty_hits);
1999 return Index(a);
2000 }
2001
2002 auto result = differences.find({a.value, b.value});
2003
2004 if (!result.is_present() MDE_EVICTION(|| is_evicted(result.get()))) {
2006 const PropertySet &first = get_value(a);
2007 const PropertySet &second = get_value(b);
2008
2009 // The difference implementation here is adapted from the example
2010 // suggested implementation provided of std::set_difference from
2011 // cppreference.com
2012 auto cursor_1 = first.begin();
2013 const auto &cursor_end_1 = first.end();
2014 auto cursor_2 = second.begin();
2015 const auto &cursor_end_2 = second.end();
2016
2017 while (cursor_1 != cursor_end_1) {
2018 if (cursor_2 == cursor_end_2) {
2020 break;
2021 }
2022
2023 if (less(*cursor_1, *cursor_2)) {
2025 cursor_1++;
2026 } else {
2027 if (!(less(*cursor_2, *cursor_1))) {
2028 if constexpr (Nesting::is_nested) {
2031 set_difference, reflist, *cursor_1, *cursor_2);
2033 }
2034 cursor_1++;
2035 }
2036 cursor_2++;
2037 }
2038 }
2039
2040 bool cold = false;
2041 Index ret;
2042
2043 MDE_EVICTION(if (result.is_present() && is_evicted(result.get())) {
2044 ret = result.get();
2045 property_sets.at_mutable(ret).reassign(new PropertySet(std::move(new_set)));
2046 } else) {
2048 differences.insert({{a.value, b.value}, ret.value});
2049
2050 if (ret != a) {
2051 store_subset(ret, a);
2052 } else {
2053 intersections.insert({
2054 {
2055 std::min(a.value, b.value),
2056 std::max(a.value, b.value)
2057 }, EMPTY_SET_VALUE});
2058 }
2059 }
2060
2061 if (cold) {
2062 MDE_PERF_INC(differences, cold_misses);
2063 } else {
2064 MDE_PERF_INC(differences, edge_misses);
2065 }
2066
2067 return Index(ret);
2068 } else {
2069 MDE_PERF_INC(differences, hits);
2070 return Index(result.get());
2071 }
2072 }
2073
2085 return set_difference(a, register_set_single(b));
2086 }
2087
2099 const PropertySet &first = get_value(a);
2100
2101 auto cursor_1 = first.begin();
2102 const auto &cursor_end_1 = first.end();
2103
2104 for (;cursor_1 != cursor_end_1; cursor_1++) {
2105 if (!PropertyEqual()(cursor_1->get_key(), p)) {
2107 }
2108 }
2109 return register_set<true>(std::move(new_set));
2110 }
2111
2121 MDE_BINARY_NESTED_OPERATION(set_intersection)
2122 Index set_intersection(const Index &_a, const Index &_b) {
2124 __mde_calc_functime(stat);
2125
2126 if (_a == _b) {
2127 MDE_PERF_INC(intersections, equal_hits);
2128 return Index(_a);
2129 }
2130
2131 if (is_empty(_a) || is_empty(_b)) {
2132 MDE_PERF_INC(intersections, empty_hits);
2133 return Index(EMPTY_SET_VALUE);
2134 }
2135
2136 const Index &a = std::min(_a, _b);
2137 const Index &b = std::max(_a, _b);
2138
2139 SubsetRelation r = is_subset(a, b);
2140
2141 if (r == SUBSET) {
2142 MDE_PERF_INC(intersections, subset_hits);
2143 return Index(a);
2144 } else if (r == SUPERSET) {
2145 MDE_PERF_INC(intersections, subset_hits);
2146 return Index(b);
2147 }
2148
2149 auto result = intersections.find({a.value, b.value});
2150
2151 if (!result.is_present() MDE_EVICTION(|| is_evicted(result.get()))) {
2153 const PropertySet &first = get_value(a);
2154 const PropertySet &second = get_value(b);
2155
2156 // The intersection implementation here is adapted from the example
2157 // suggested implementation provided for std::set_intersection from
2158 // cppreference.com
2159 auto cursor_1 = first.begin();
2160 const auto &cursor_end_1 = first.end();
2161 auto cursor_2 = second.begin();
2162 const auto &cursor_end_2 = second.end();
2163
2165 {
2166 if (less(*cursor_1,*cursor_2)) {
2167 cursor_1++;
2168 } else {
2169 if (!(less(*cursor_2, *cursor_1))) {
2170 if constexpr (Nesting::is_nested) {
2172 MDE_PERFORM_BINARY_NESTED_OPERATION(set_intersection, reflist, *cursor_1, *cursor_2);
2174 } else {
2176 }
2177 cursor_1++;
2178 }
2179 cursor_2++;
2180 }
2181 }
2182
2183 bool cold = false;
2184 Index ret;
2185
2186 MDE_EVICTION(if (result.is_present() && is_evicted(result.get())) {
2187 ret = result.get();
2188 property_sets.at_mutable(ret).reassign(new PropertySet(std::move(new_set)));
2189 } else){
2191 intersections.insert({{a.value, b.value}, ret.value});
2192
2193 if (ret != a) {
2194 store_subset(ret, a);
2195 } else if (ret != b) {
2196 store_subset(ret, b);
2197 } else {
2198 store_subset(ret, a);
2199 store_subset(ret, b);
2200 }
2201 }
2202
2203 if (cold) {
2204 MDE_PERF_INC(intersections, cold_misses);
2205 } else {
2206 MDE_PERF_INC(intersections, edge_misses);
2207 }
2208 return Index(ret);
2209 }
2210
2211 MDE_PERF_INC(intersections, hits);
2212 return Index(result.get());
2213 }
2214
2215
2232 Index s,
2233 std::function<bool(const PropertyElement &)> filter_func,
2236 __mde_calc_functime(stat);
2237
2238 if (is_empty(s)) {
2239 return s;
2240 }
2241
2242 auto result = cache.find(s.value);
2243
2244 if (!result.is_present() MDE_EVICTION(|| is_evicted(result.get()))) {
2246 for (const PropertyElement &value : get_value(s)) {
2247 if (filter_func(value)) {
2248 MDE_PUSH_ONE(new_set, value);
2249 }
2250 }
2251
2252 bool cold;
2253 Index ret;
2254
2255 MDE_EVICTION(if (result.is_present() && is_evicted(result.get())) {
2256 ret = result.get();
2257 property_sets.at_mutable(ret).reassign(new PropertySet(std::move(new_set)));
2258 } else) {
2260 cache.insert(std::make_pair(s.value, ret.value));
2261 }
2262
2263 if (cold) {
2264 MDE_PERF_INC(filter, cold_misses);
2265 } else {
2266 MDE_PERF_INC(filter, edge_misses);
2267 }
2268
2269 return Index(ret);
2270 } else {
2271 MDE_PERF_INC(filter, hits);
2272 return Index(result.get());
2273 }
2274 }
2275
2284 std::stringstream s;
2285 s << "{ ";
2286 for (const PropertyElement &p : set) {
2287 s << p.to_string() << " ";
2288 }
2289 s << "}";
2290
2291 return s.str();
2292 }
2293
2295 return property_set_to_string(get_value(idx));
2296 }
2297
2298#ifdef MDE_ENABLE_SERIALIZATION
2299
2300 const RefList &get_reflist() const {
2301 return reflist;
2302 }
2303
2304 virtual slz::JSON operations_to_json() const {
2305 slz::JSON ret = slz::JSON::object();
2306 ret["unions"] = slz::binary_operation_map_to_json(unions);
2307 ret["intersections"] = slz::binary_operation_map_to_json(intersections);
2308 ret["differences"] = slz::binary_operation_map_to_json(differences);
2309 ret["subsets"] = slz::binary_operation_map_to_json(subsets);
2310 return ret;
2311 }
2312
2313 virtual void operations_from_json(const slz::JSON &obj) {
2314 std::cout << obj.dump() << std::endl;
2315 slz::binary_operation_map_from_json(unions, obj["unions"]);
2316 slz::binary_operation_map_from_json(intersections, obj["intersections"]);
2317 slz::binary_operation_map_from_json(differences, obj["differences"]);
2318 slz::binary_operation_map_from_json(subsets, obj["subsets"]);
2319 }
2320
2321 template<typename Serializer =
2322 slz::DefaultValueSerializer<PropertyT>>
2323 slz::JSON to_json(Serializer &s) const {
2324 slz::JSON ret = slz::JSON::object();
2325
2326 if constexpr (Nesting::is_nested) {
2327 ret["property_sets"] =
2328 slz::storage_array_to_json_nested(property_sets, s);
2329 } else {
2330 ret["property_sets"] =
2331 slz::storage_array_to_json(property_sets, s);
2332 }
2333
2334 ret["operations"] = operations_to_json();
2335
2336 return ret;
2337 }
2338
2339 template<typename Serializer =
2340 slz::DefaultValueSerializer<PropertyT>>
2341 slz::JSON to_json() const {
2342 auto s = Serializer();
2343 return to_json(s);
2344 }
2345
2346 template<typename Serializer =
2347 slz::DefaultValueSerializer<PropertyT>>
2348 void load_from_json(const slz::JSON &obj, Serializer &s) {
2349 clear();
2350 operations_from_json(obj["operations"]);
2351 if constexpr (Nesting::is_nested) {
2352 slz::register_storage_from_json_nested(*this, obj["property_sets"], s);
2353 } else {
2354 slz::register_storage_from_json(*this, obj["property_sets"], s);
2355 }
2356 }
2357
2358 template<typename Serializer =
2359 slz::DefaultValueSerializer<PropertyT>>
2360 void load_from_json(const slz::JSON &obj) {
2361 auto s = Serializer();
2362 load_from_json(obj, s);
2363 }
2364
2365#endif
2366
2370 String dump() const {
2371 std::stringstream s;
2372
2373 s << "{\n";
2374
2375 s << " " << "Unions: " << "(Count: " << unions.size() << ")\n";
2376 s << unions.to_string();
2377 s << "\n";
2378
2379 s << " " << "Differences:" << "(Count: " << differences.size() << ")\n";
2380 s << differences.to_string();
2381 s << "\n";
2382
2383 s << " " << "Intersections: " << "(Count: " << intersections.size() << ")\n";
2384 s << intersections.to_string();
2385 s << "\n";
2386
2387 s << " " << "Subsets: " << "(Count: " << subsets.size() << ")\n";
2388 for (auto i : subsets) {
2389 s << " " << i.first << " -> " << (i.second == SUBSET ? "sub" : "sup") << "\n";
2390 }
2391 s << "\n";
2392
2393 s << " " << "PropertySets: " << "(Count: " << property_sets.size() << ")\n";
2394 for (size_t i = 0; i < property_sets.size(); i++) {
2395 s << " "
2396 << i << " : " << property_set_to_string(*property_sets.at(i).get()) << "\n";
2397 }
2398 s << "}\n";
2399
2400 return s.str();
2401 }
2402
2403 friend std::ostream& operator<<(std::ostream& os, const MDENode& obj) {
2404 os << obj.dump();
2405 return os;
2406 }
2407
2408#ifdef MDE_ENABLE_PERFORMANCE_METRICS
2417 std::stringstream s;
2418 s << "Performance Profile: \n";
2419 for (auto &p : perf) {
2420 s << p.first << "\n"
2421 << p.second.to_string() << "\n";
2422 }
2423 s << stat.dump();
2424 return s.str();
2425 }
2426#endif
2427
2428}; // END MDENode
2429
2430
2433#define MDE_PROPERTY_INDEX_VALID(__index) { \
2434 _Pragma("GCC diagnostic push"); \
2435 _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
2436 if ((__index.value) < 0 || ((__index.value) > property_list.size() - 1)) { \
2437 throw __MDE_EXCEPT("Invalid index supplied"); \
2438 } \
2439 _Pragma("GCC diagnostic pop") \
2440}
2441
2458template <
2459 typename PropertyT,
2460 typename PropertyHash = DefaultHash<PropertyT>,
2461 typename PropertyEqual = DefaultEqual<PropertyT>,
2462 typename PropertyPrinter = DefaultPrinter<PropertyT>>
2468 struct Index {
2470
2471 Index(IndexValue idx = EMPTY_SET_VALUE): value(idx) {}
2472
2473 bool is_empty() const {
2474 return value == EMPTY_SET_VALUE;
2475 }
2476
2477 bool operator==(const Index &b) const {
2478 return value == b.value;
2479 }
2480
2481 bool operator!=(const Index &b) const {
2482 return value != b.value;
2483 }
2484
2485 bool operator<(const Index &b) const {
2486 return value < b.value;
2487 }
2488
2489 bool operator>(const Index &b) const {
2490 return value > b.value;
2491 }
2492
2494 return std::to_string(value);
2495 }
2496
2497 friend std::ostream& operator<<(std::ostream& os, const Index& obj) {
2498 os << obj.to_string();
2499 return os;
2500 }
2501
2502 struct Hash {
2503 Size operator()(const Index &idx) const {
2504 return DefaultHash<IndexValue>()(idx.value);
2505 }
2506 };
2507 };
2508
2510 Size operator()(const PropertyT *p) const {
2511 return PropertyHash()(*p);
2512 }
2513 };
2514
2516 Size operator()(const PropertyT *a, const PropertyT *b) const {
2517 return PropertyEqual()(*a, *b);
2518 }
2519 };
2520
2522 std::unordered_map<
2523 PropertyT *, IndexValue,
2526
2527 // The property storage array.
2529
2530 // The property -> Index in storage array mapping.
2531 PropertyMap property_map = {};
2532
2543 Index register_value(PropertyT &c) {
2544 auto cursor = property_map.find(&c);
2545
2546 if (cursor == property_map.end()) {
2548 UniquePointer<PropertyT>(new PropertyT(c));
2549 property_list.push_back(std::move(new_value));
2550 IndexValue ret = property_list.size() - 1;
2551 property_map.insert(std::make_pair(property_list[ret].get(), ret));
2552 return Index(ret);
2553 }
2554 return Index(cursor->second);
2555 }
2556
2557 Index register_value(PropertyT &&c) {
2558 auto cursor = property_map.find(&c);
2559
2560 if (cursor == property_map.end()) {
2562 UniquePointer<PropertyT>(new PropertyT(std::move(c)));
2563 property_list.push_back(std::move(new_value));
2564 IndexValue ret = property_list.size() - 1;
2565 property_map.insert(std::make_pair(property_list[ret].get(), ret));
2566 return Index(ret);
2567 }
2568 return Index(cursor->second);
2569 }
2570
2578 Index register_ptr(PropertyT *c) {
2579 auto cursor = property_map.find(c);
2580
2581 if (cursor == property_map.end()) {
2583 property_list.push_back(std::move(new_value));
2584 IndexValue ret = property_list.size() - 1;
2585 property_map.insert(std::make_pair(property_list[ret].get(), ret));
2586 return Index(ret);
2587 }
2588 delete c;
2589 return Index(cursor->second);
2590 }
2591
2593 return property_list.size();
2594 }
2595
2596 const PropertyT &get_value(Index id) const {
2598 return *property_list[id.value].get();
2599 }
2600
2605 const PropertyT *get_value_ptr(Index id) const {
2607 return property_list[id.value].get();
2608 }
2609
2610 std::string dump() const {
2611 std::stringstream s;
2612 s << "Deduplicator Stored Data: "
2613 << "(Size = " << property_list.size() <<") {" << std::endl;
2614 for (Size i = 0; i < get_property_count(); i++) {
2615 s << " " << i << ": "
2616 << PropertyPrinter()(get_value(i)) << std::endl;
2617 }
2618 s << "}" << std::endl;
2619
2620 return s.str();
2621 }
2622
2623};
2624
2625}; // END NAMESPACE
2626
2627#endif
const PropertySetHolder & at(const Index &idx) const
Definition mde.hpp:1282
Index push_back(PropertySetHolder &&p)
Definition mde.hpp:1286
PropertySetHolder & at_mutable(const Index &idx) const
Retuns a mutable reference to the property set holder at a given set index. This is useful for evicti...
Definition mde.hpp:1278
The main MDENode structure. This class can be used as-is with a type or derived for additional functi...
Definition mde.hpp:951
virtual void clear()
Removes all data from the MDE.
Definition mde.hpp:1337
static bool less_key(const PropertyElement &a, const PropertyElement &b)
Definition mde.hpp:1732
typename Config::PropertyHash PropertyHash
Definition mde.hpp:955
OperationMap< OperationNode > BinaryOperationMap
Definition mde.hpp:1079
static bool equal(const PropertyElement &a, const PropertyElement &b)
Equality comparator for operations. You MUST use this instead of directly using anything else like "<...
Definition mde.hpp:1745
HashMap< String, OperationPerf > perf
Definition mde.hpp:1087
void clear_and_initialize()
Resets state of the MDE to the default.
Definition mde.hpp:1359
typename Nesting::MDEReferenceList RefList
Definition mde.hpp:1080
SetEqual< PropertySet, PropertyElement, typename PropertyElement::FullEqual > PropertySetFullEqual
Definition mde.hpp:1037
static bool less(const PropertyElement &a, const PropertyElement &b)
Less than comparator for operations. You MUST use this instead of directly using anything else like "...
Definition mde.hpp:1724
Size size_of(const Index &index) const
Returns the size of the set at index
Definition mde.hpp:1707
void store_subset(const Index &a, const Index &b)
Stores index a as the subset of index b if a < b, else stores index a as the superset of index b
Definition mde.hpp:1321
bool is_empty(const Index &i) const
Definition mde.hpp:1352
MDENode(RefList reflist={})
Definition mde.hpp:1347
SubsetRelation is_subset(const Index &a, const Index &b) const
Returns whether we currently know whether a is a subset or a superset of b.
Definition mde.hpp:1373
const PropertySet & get_value(const Index &index) const
Gets the actual property set specified by index.
Definition mde.hpp:1681
Index register_set(Iterator begin, Iterator end)
Definition mde.hpp:1600
friend std::ostream & operator<<(std::ostream &os, const MDENode &obj)
Definition mde.hpp:2403
NestingT Nesting
Definition mde.hpp:958
Index register_set(PropertySet &&c, bool &cold)
Definition mde.hpp:1568
OperationMap< IndexValue > UnaryOperationMap
Definition mde.hpp:1078
void prepare_vector_set(PropertySet &c)
Definition mde.hpp:1465
Index register_set(Iterator begin, Iterator end, bool &cold)
Definition mde.hpp:1629
typename Config::PropertyPrinter PropertyPrinter
Definition mde.hpp:957
Index set_remove_single_key(const Index &a, const PropertyT &p)
Removes a single element from a given set if the "key" element matches.
Definition mde.hpp:2097
Index register_set_single(const PropertyElement &c, bool &cold)
Inserts a (or gets an existing) single-element set into the property set storage, and reports whether...
Definition mde.hpp:1430
static bool equal_key(const PropertyElement &a, const PropertyElement &b)
Definition mde.hpp:1753
static bool equal_key(const PropertyElement &a, const PropertyT &b)
Definition mde.hpp:1749
bool contains(const Index &index, const PropertyElement &prop) const
Determines whether the property set at index contains the element prop or not.
Definition mde.hpp:1810
typename Config::PropertyT PropertyT
Definition mde.hpp:953
String property_set_to_string(const Index &idx) const
Definition mde.hpp:2294
static String property_set_to_string(const PropertySet &set)
Converts the property set to a string.
Definition mde.hpp:2283
static bool less_key(const PropertyElement &a, const PropertyT &b)
Definition mde.hpp:1728
SetHash< PropertySet, PropertyElement, typename PropertyElement::Hash > PropertySetHash
Definition mde.hpp:1031
String dump_perf() const
Dumps performance information as a string.
Definition mde.hpp:2416
Index register_set_single(const PropertyElement &c)
Inserts a (or gets an existing) single-element set into property set storage.
Definition mde.hpp:1395
typename Nesting::template PropertyElement< PropertyLess, PropertyHash, PropertyEqual, PropertyPrinter > PropertyElement
Definition mde.hpp:1019
String dump() const
Dumps the current state of the MDE to a string.
Definition mde.hpp:2370
Index set_insert_single(const Index &a, const PropertyElement &b)
Inserts a single element from a given set (and returns the index of the set). This is a wrapper over ...
Definition mde.hpp:1971
RefList reflist
Definition mde.hpp:1083
Index register_set(const PropertySet &c, bool &cold)
Definition mde.hpp:1508
Index register_set(PropertySet &&c)
Definition mde.hpp:1540
Size property_set_count() const
Returns the total number of property sets currently in the MDE.
Definition mde.hpp:1696
Index set_remove_single(const Index &a, const PropertyElement &b)
Removes a single element from a given set (and returns the index of the set). This is a wrapper over ...
Definition mde.hpp:2084
Index set_filter(Index s, std::function< bool(const PropertyElement &)> filter_func, UnaryOperationMap &cache)
Filters a set based on a criterion function. This is supposed to be an abstract filtering mechanism t...
Definition mde.hpp:2231
typename Config::PropertyLess PropertyLess
Definition mde.hpp:954
typename Config::PropertyEqual PropertyEqual
Definition mde.hpp:956
OptionalRef< PropertyElement > find_key(const Index &index, const PropertyT &p) const
Finds a property element in the set based on the key provided.
Definition mde.hpp:1767
std::vector< PropertyElement > PropertySet
Definition mde.hpp:1025
PerformanceStatistics stat
Definition mde.hpp:1086
Index register_set(const PropertySet &c)
Definition mde.hpp:1480
typename Map::mapped_type MappedType
Definition mde.hpp:780
Size size() const
Definition mde.hpp:808
Optional< MappedType > find(const Key &key) const
Definition mde.hpp:788
Map::const_iterator begin() const
Definition mde.hpp:813
void insert(KeyValuePair &&v)
Definition mde.hpp:798
MapClass Map
Definition mde.hpp:778
String to_string() const
Definition mde.hpp:821
typename Map::key_type Key
Definition mde.hpp:779
Map::const_iterator end() const
Definition mde.hpp:817
void clear()
Definition mde.hpp:803
typename Map::value_type KeyValuePair
Definition mde.hpp:781
Describes an optional reference of some type T. The value may either be present or absent.
Describes an optional of some type T. The value may either be present or absent.
static Optional absent()
Explicitly creates an absent value.
#define __MDE_ASSERT(__cond, __msg_arg)
Definition mde.hpp:205
#define MDE_PARALLEL(__x)
Definition mde.hpp:309
#define MDE_PROPERTY_SET_INDEX_VALID(__index)
Check whether the index is a valid index within the property set.
Definition mde.hpp:278
#define MDE_BINARY_NESTED_OPERATION(__op_name)
Declares a struct that enables the recursive/nesting behaviour of an operation.
Definition mde.hpp:481
#define MDE_PROPERTY_SET_INTEGRITY_VALID(__set)
Macro and switch for verify_property_set_integrity inside MDE.
Definition mde.hpp:251
#define MDE_PUSH_ONE(__cont, __val)
Pushes one element to a PropertySet. Use this when implementing operations.
Definition mde.hpp:327
#define MDE_PROPERTY_INDEX_VALID(__index)
Definition mde.hpp:2433
#define MDE_REGISTER_SET_INTERNAL(__set, __cold)
Registers a set with behaviours defined for internal processing.
Definition mde.hpp:349
#define MDE_PROPERTY_SET_PAIR_UNEQUAL(__index1, __index2)
Check whether the pair of indexes are unequal. Used for sanity checking.
Definition mde.hpp:293
#define MDE_PERF_INC(__oper, __category)
Increments the invocation count of the given category and operator.
Definition mde.hpp:910
#define MDE_EVICTION(__x)
Definition mde.hpp:315
#define MDE_PROPERTY_SET_PAIR_VALID(__index1, __index2)
Check whether the pair of indexes is a valid within the property set.
Definition mde.hpp:288
#define MDE_PERFORM_BINARY_NESTED_OPERATION(__op_name, __reflist, __arg1, __arg2)
Actually enables the nesting. this must be placed in the operation body where the nested behaviour is...
Definition mde.hpp:500
#define MDE_PUSH_RANGE(__cont, __start, __end)
Pushes a range of elements to a PropertySet using an iterator. Use this when implementing operations.
Definition mde.hpp:339
Any common components go into this file.
#define MDE_DEFAULT_BLOCK_MASK
#define MDE_DEFAULT_BLOCK_SIZE
#define MDE_DEFAULT_BLOCK_SHIFT
#define MDE_SORTED_VECTOR_BINARY_SEARCH_THRESHOLD
Definition mde.hpp:16
SubsetRelation
Used to store a subset relation between two set indices. Because the index pair must be in sorted ord...
@ UNKNOWN
@ SUPERSET
MapAdapter< HashMap< K, V > > InternalMap
Definition mde.hpp:850
std::size_t Size
std::string String
Size IndexValue
std::ostream & operator<<(std::ostream &os, const OperationNode &op)
Definition mde.hpp:41
std::hash< T > DefaultHash
InternalMap< T, IndexValue > OperationMap
Definition mde.hpp:859
Enables basic code-based profiling metrics in MDE.
#define __mde_calc_functime(__stat)
Creates a timer object to capture duration of the current function when going out of scope.
Struct that is thrown on an assertion failure.
Definition mde.hpp:189
AssertError(const std::string &message)
Definition mde.hpp:190
Size operator()(const Index &idx) const
Definition mde.hpp:2503
Index returned by the class. Being defined inside the class ensures type safety and possible future e...
Definition mde.hpp:2468
bool operator<(const Index &b) const
Definition mde.hpp:2485
bool operator!=(const Index &b) const
Definition mde.hpp:2481
bool is_empty() const
Definition mde.hpp:2473
bool operator==(const Index &b) const
Definition mde.hpp:2477
friend std::ostream & operator<<(std::ostream &os, const Index &obj)
Definition mde.hpp:2497
String to_string() const
Definition mde.hpp:2493
Index(IndexValue idx=EMPTY_SET_VALUE)
Definition mde.hpp:2471
bool operator>(const Index &b) const
Definition mde.hpp:2489
Size operator()(const PropertyT *a, const PropertyT *b) const
Definition mde.hpp:2516
Size operator()(const PropertyT *p) const
Definition mde.hpp:2510
An straightforward deduplicator for scalar values. It does not implement any special operations besid...
Definition mde.hpp:2463
Size get_property_count() const
Definition mde.hpp:2592
const PropertyT * get_value_ptr(Index id) const
Definition mde.hpp:2605
Index register_value(PropertyT &&c)
Definition mde.hpp:2557
const PropertyT & get_value(Index id) const
Definition mde.hpp:2596
Index register_value(PropertyT &c)
Inserts a (or gets an existing) element into property storage.
Definition mde.hpp:2543
std::string dump() const
Definition mde.hpp:2610
std::unordered_map< PropertyT *, IndexValue, PropertyPtrHash, PropertyPtrEqual > PropertyMap
Definition mde.hpp:2525
Index register_ptr(PropertyT *c)
Definition mde.hpp:2578
DefaultHash< PropertyT > PropertyHash
Definition mde.hpp:921
DefaultPrinter< PropertyT > PropertyPrinter
Definition mde.hpp:923
DefaultEqual< PropertyT > PropertyEqual
Definition mde.hpp:922
DefaultLess< PropertyT > PropertyLess
Definition mde.hpp:920
Size operator()(const Index &idx) const
Definition mde.hpp:1004
Index returned by an operation. Being defined inside the class ensures type safety and possible futur...
Definition mde.hpp:969
bool operator<(const Index &b) const
Definition mde.hpp:986
bool is_empty() const
Definition mde.hpp:974
bool operator!=(const Index &b) const
Definition mde.hpp:982
friend std::ostream & operator<<(std::ostream &os, const Index &obj)
Definition mde.hpp:998
bool operator==(const Index &b) const
Definition mde.hpp:978
String to_string() const
Definition mde.hpp:994
bool operator>(const Index &b) const
Definition mde.hpp:990
Index(IndexValue idx=EMPTY_SET_VALUE)
Definition mde.hpp:972
IndexValue value
Definition mde.hpp:970
UniquePointer< PropertySet > PtrContainer
Definition mde.hpp:1091
typename PtrContainer::pointer Ptr
Definition mde.hpp:1092
This forces a comparison of both the key and the value instead of only the key. Required in instances...
Definition mde.hpp:698
bool operator()(const PropertyElement &a, const PropertyElement &b) const
Definition mde.hpp:699
Size operator()(const PropertyElement &p) const
Definition mde.hpp:687
Type for the elements for a property set in the nested. The template arguments are for the 'key' type...
Definition mde.hpp:545
const ChildValueListIndexType< ListIndex > & value() const
Gets the first object in the tuple of the nested values.
Definition mde.hpp:599
PropertyT InterfaceValueType
Value type is made available here if required by user.
Definition mde.hpp:551
const ChildValueListIndexType< 0 > & value0() const
Definition mde.hpp:603
bool operator==(const PropertyElement &b) const
Definition mde.hpp:665
const ChildValueList & get_value() const
Gets the nested value. It returns a tuple of values containing indices to each of the nested sets of ...
Definition mde.hpp:589
bool operator<(const PropertyElement &b) const
Definition mde.hpp:661
PropertyT InterfaceKeyType
Key type is made available here if required by user.
Definition mde.hpp:548
PropertyElement apply(const MDEReferenceList &mde, const PropertyElement &arg) const
Performs the "apply" operation on the list of nested children specified by the Operation parameter.
Definition mde.hpp:649
const PropertyT & key() const
Gets the 'key' value. Synonymous with get_key.
Definition mde.hpp:578
friend std::ostream & operator<<(std::ostream &os, const PropertyElement &obj)
Definition mde.hpp:681
const PropertyT & get_key() const
Gets the 'key' value.
Definition mde.hpp:569
void apply_internal(ChildValueList &ret, const MDEReferenceList &mde, const ChildValueList &arg_value, std::index_sequence< Indices... >) const
Actually performs the template "apply" operation. This sets up template syntax to go over each elemen...
Definition mde.hpp:624
PropertyElement(const PropertyT &key, const ChildValueList &value)
Definition mde.hpp:558
Describes the standard nesting structure. Act as "non-leaf" nodes in a tree of nested MDEs.
Definition mde.hpp:511
static constexpr Size num_children
Definition mde.hpp:517
std::tuple< typename ChildT::Index... > ChildValueList
Definition mde.hpp:524
std::tuple< ChildT &... > MDEReferenceList
Reference list. References to all the nested MDEs are presented here.
Definition mde.hpp:520
typename std::tuple_element< ListIndex, ChildValueList >::type ChildValueListIndexType
Gets the type of a particular index in the child value list tuple.
Definition mde.hpp:529
static constexpr bool is_nested
Compile-time value that says this is nested.
Definition mde.hpp:513
This forces a comparison of both the key and the value instead of only the key. Required in instances...
Definition mde.hpp:461
bool operator()(const PropertyElement &a, const PropertyElement &b) const
Definition mde.hpp:462
Size operator()(const PropertyElement &p) const
Definition mde.hpp:447
Base-case type for the elements for a property set. The template arguments are for the 'key' type.
Definition mde.hpp:386
PropertyT InterfaceKeyType
Key type is made available here if required by user.
Definition mde.hpp:389
bool operator<(const PropertyElement &b) const
Definition mde.hpp:429
bool operator==(const PropertyElement &b) const
Definition mde.hpp:433
PropertyT InterfaceValueType
Value type is made available here if required by user.
Definition mde.hpp:392
friend std::ostream & operator<<(std::ostream &os, const PropertyElement &obj)
Definition mde.hpp:441
const PropertyT & get_key() const
Gets the 'key' value.
Definition mde.hpp:405
PropertyElement(const PropertyT &value)
Definition mde.hpp:398
const PropertyT & get_value() const
Gets the nested value. In the base case it simply returns the key.
Definition mde.hpp:415
PropertyElement apply() const
Performs an "apply" operation. In the base case it is an identity operation and does not do anything.
Definition mde.hpp:425
The nesting type for non-nested data structures. Act as "leaf" nodes in a tree of nested MDEs.
Definition mde.hpp:358
std::tuple<> MDEReferenceList
Reference list. In the base case, there are no child MDEs.
Definition mde.hpp:367
static constexpr Size num_children
Compile-time value that says there are no nested children.
Definition mde.hpp:363
std::tuple<> ChildValueList
Child value list. In the base case, there are no child MDEs.
Definition mde.hpp:370
static constexpr bool is_nested
Compile-time value that says this is not nested.
Definition mde.hpp:360
This struct contains the information about the operands of an operation (union, intersection,...
Definition mde.hpp:22
IndexValue left
Definition mde.hpp:23
bool operator<(const OperationNode &op) const
Definition mde.hpp:32
std::string to_string() const
Definition mde.hpp:26
IndexValue right
Definition mde.hpp:24
bool operator==(const OperationNode &op) const
Definition mde.hpp:36
Operation performance Statistics.
Definition mde.hpp:864
String to_string() const
Definition mde.hpp:887
Utility class for enabling code-based profiling.
Definition profiling.hpp:24
Generic Equality comparator for set types.
Definition mde.hpp:133
bool operator()(const SetT *a, const SetT *b) const
Definition mde.hpp:134
Hasher for set types.
Definition mde.hpp:109
Size operator()(const SetT *k) const
Definition mde.hpp:110
Generic Less-than comparator for set types.
Definition mde.hpp:71
bool operator()(const OrderedSetT *a, const OrderedSetT *b) const
Definition mde.hpp:72
Thrown if code region is unreachable.
Definition mde.hpp:197
Unreachable(const std::string &message="Hit a branch marked as unreachable.")
Definition mde.hpp:198
mde::Size operator()(const mde::OperationNode &k) const
Definition mde.hpp:51