• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision459 (tree)
Time2022-04-19 20:45:58
Authorquiret

Log Message

- various adjustments around the codebase
- added eir::containNotify(Add-)RemoveTie tuples for compact addition/removal notification of container/field entries by using eir::replaceInContainer/eir::removeFromContainer + unit-tests

Change Summary

Incremental Difference

--- common/sdk/Iterate.h (revision 458)
+++ common/sdk/Iterate.h (revision 459)
@@ -18,9 +18,160 @@
1818 #include "Set.h"
1919 #include "MultiValueStore.h"
2020
21+#include <type_traits>
22+
2123 namespace eir
2224 {
2325
26+// Modification tie as helper.
27+template <typename containerType, typename addCallbackType, typename removeCallbackType>
28+struct containNotifyAddRemoveTie
29+{
30+ typedef containerType containerType;
31+
32+ template <typename itemType>
33+ using is_about = std::bool_constant <
34+ std::is_invocable <addCallbackType, itemType>::value && std::is_invocable <removeCallbackType, itemType>::value
35+ >;
36+
37+ AINLINE containNotifyAddRemoveTie( containerType& container, addCallbackType& add_cb, removeCallbackType& rem_cb ) noexcept
38+ : container( container ), add_cb( add_cb ), rem_cb( rem_cb )
39+ {
40+ return;
41+ }
42+ containNotifyAddRemoveTie( containNotifyAddRemoveTie&& ) = default;
43+ containNotifyAddRemoveTie( const containNotifyAddRemoveTie& ) = default;
44+
45+ AINLINE containNotifyAddRemoveTie& operator = ( containNotifyAddRemoveTie&& ) = default;
46+ AINLINE containNotifyAddRemoveTie& operator = ( const containNotifyAddRemoveTie& ) = default;
47+
48+ AINLINE containerType& GetContainer( void ) noexcept
49+ {
50+ return this->container;
51+ }
52+ AINLINE addCallbackType& GetAddCallback( void ) noexcept
53+ {
54+ return this->add_cb;
55+ }
56+ AINLINE removeCallbackType& GetRemoveCallback( void ) noexcept
57+ {
58+ return this->rem_cb;
59+ }
60+
61+ AINLINE operator containerType& ( void ) noexcept
62+ {
63+ return this->container;
64+ }
65+ AINLINE operator const containerType& ( void ) const noexcept
66+ {
67+ return this->container;
68+ }
69+
70+private:
71+ [[no_unique_address]] containerType& container;
72+ [[no_unique_address]] addCallbackType& add_cb;
73+ [[no_unique_address]] removeCallbackType& rem_cb;
74+};
75+
76+// Deducation guides.
77+template <typename containerType, typename addCallbackType, typename removeCallbackType>
78+containNotifyAddRemoveTie( containerType& container, addCallbackType add_cb, removeCallbackType rem_cb ) -> containNotifyAddRemoveTie <containerType, const addCallbackType, const removeCallbackType>;
79+
80+// Mandatory type-trait.
81+template <typename>
82+struct is_contain_notify_add_remove_tie : std::false_type
83+{};
84+template <typename... tieArgs>
85+struct is_contain_notify_add_remove_tie <containNotifyAddRemoveTie <tieArgs...>> : std::true_type
86+{};
87+template <typename... tieArgs>
88+struct is_contain_notify_add_remove_tie <const containNotifyAddRemoveTie <tieArgs...>> : std::true_type
89+{};
90+template <typename... tieArgs>
91+struct is_contain_notify_add_remove_tie <containNotifyAddRemoveTie <tieArgs...>&> : std::true_type
92+{};
93+template <typename... tieArgs>
94+struct is_contain_notify_add_remove_tie <const containNotifyAddRemoveTie <tieArgs...>&> : std::true_type
95+{};
96+template <typename... tieArgs>
97+struct is_contain_notify_add_remove_tie <containNotifyAddRemoveTie <tieArgs...>&&> : std::true_type
98+{};
99+template <typename... tieArgs>
100+struct is_contain_notify_add_remove_tie <const containNotifyAddRemoveTie <tieArgs...>&&> : std::true_type
101+{};
102+
103+// A tie which stores just a removal callback.
104+template <typename containerType, typename removeCallbackType>
105+struct containNotifyRemoveTie
106+{
107+ typedef containerType containerType;
108+
109+ template <typename itemType>
110+ using is_about = std::bool_constant <
111+ std::is_invocable <removeCallbackType, itemType>::value
112+ >;
113+
114+ AINLINE containNotifyRemoveTie( containerType& container, removeCallbackType& rem_cb ) noexcept
115+ : container( container ), rem_cb( rem_cb )
116+ {
117+ return;
118+ }
119+ AINLINE containNotifyRemoveTie( containNotifyRemoveTie&& ) = default;
120+ AINLINE containNotifyRemoveTie( const containNotifyRemoveTie& ) = default;
121+
122+ AINLINE containNotifyRemoveTie& operator = ( containNotifyRemoveTie&& ) = default;
123+ AINLINE containNotifyRemoveTie& operator = ( const containNotifyRemoveTie& ) = default;
124+
125+ AINLINE containerType& GetContainer( void ) noexcept
126+ {
127+ return this->container;
128+ }
129+ AINLINE removeCallbackType& GetRemoveCallback( void ) noexcept
130+ {
131+ return this->rem_cb;
132+ }
133+
134+ AINLINE operator containerType& ( void ) noexcept
135+ {
136+ return this->container;
137+ }
138+ AINLINE operator const containerType& ( void ) const noexcept
139+ {
140+ return this->container;
141+ }
142+
143+private:
144+ [[no_unique_address]] containerType& container;
145+ [[no_unique_address]] removeCallbackType& rem_cb;
146+};
147+
148+// Deducation guides.
149+template <typename containerType, typename removeCallbackType>
150+containNotifyRemoveTie( containerType&, removeCallbackType ) -> containNotifyRemoveTie <containerType, const removeCallbackType>;
151+
152+// Mandatory type-trait.
153+template <typename>
154+struct is_contain_notify_remove_tie : std::false_type
155+{};
156+template <typename... tieArgs>
157+struct is_contain_notify_remove_tie <containNotifyRemoveTie <tieArgs...>> : std::true_type
158+{};
159+template <typename... tieArgs>
160+struct is_contain_notify_remove_tie <const containNotifyRemoveTie <tieArgs...>> : std::true_type
161+{};
162+template <typename... tieArgs>
163+struct is_contain_notify_remove_tie <containNotifyRemoveTie <tieArgs...>&> : std::true_type
164+{};
165+template <typename... tieArgs>
166+struct is_contain_notify_remove_tie <const containNotifyRemoveTie <tieArgs...>&> : std::true_type
167+{};
168+template <typename... tieArgs>
169+struct is_contain_notify_remove_tie <containNotifyRemoveTie <tieArgs...>&&> : std::true_type
170+{};
171+template <typename... tieArgs>
172+struct is_contain_notify_remove_tie <const containNotifyRemoveTie <tieArgs...>&&> : std::true_type
173+{};
174+
24175 // Iterates over a single item/container.
25176 template <typename itemType, typename containerType, typename callbackType>
26177 requires ( eir::constructible_from <itemType, containerType&&> && std::is_invocable <callbackType, itemType&&>::value ||
@@ -83,48 +234,129 @@
83234
84235 template <typename findItemType, typename putItemType, typename... containerTypes>
85236 requires ( sizeof...( containerTypes ) > 0 && ( std::is_const <containerTypes>::value || ... ) == false )
86-AINLINE void replaceInContainer( const findItemType& oldval, const putItemType& newval, containerTypes&&... containers )
237+AINLINE void replaceInContainer( const findItemType& oldval, putItemType&& newval, containerTypes&&... containers )
87238 {
88239 auto _replace_lambda = [&]( auto& container ) LAINLINE
89240 {
90- if constexpr ( is_set <decltype(container)>::value )
241+ // I have to separate the two code-graphs because there is no compile-time splicing of variable names
242+ // possible using simple notation. In that case I prefer to have full control in shaping the possibly-
243+ // incompatible future.
244+ if constexpr ( is_contain_notify_add_remove_tie <decltype(container)>::value )
91245 {
92- if ( auto *foundNode = container.Find( oldval ) )
246+ auto& real_container = container.GetContainer();
247+
248+ if constexpr ( is_set <decltype(real_container)>::value )
93249 {
94- auto& upd = container.BeginNodeUpdate( foundNode );
250+ if ( auto *foundNode = real_container.Find( oldval ) )
251+ {
252+ auto& upd = real_container.BeginNodeUpdate( foundNode );
95253
96- upd = newval;
254+ container.GetRemoveCallback()( upd );
97255
98- container.EndNodeUpdate( foundNode );
256+ upd = std::forward <putItemType> ( newval );
257+
258+ container.GetAddCallback()( upd );
259+
260+ real_container.EndNodeUpdate( foundNode );
261+ }
99262 }
100- }
101- else if constexpr ( is_multivaluestore <decltype(container)>::value )
102- {
103- container.Replace( oldval, newval );
104- }
105- else if constexpr ( is_vector <decltype(container)>::value )
106- {
107- container.ReplaceValues( oldval, newval );
108- }
109- else if constexpr (
110- std::is_reference <decltype(container)>::value &&
111- std::convertible_to <putItemType, typename std::remove_reference <decltype(container)>::type>
112- )
113- {
114- if ( container == oldval )
263+ else if constexpr ( is_multivaluestore <decltype(real_container)>::value )
115264 {
116- container = newval;
265+ bool replaced = real_container.Replace( oldval, newval );
266+
267+ if ( replaced )
268+ {
269+ container.GetRemoveCallback()( oldval );
270+ container.GetAddCallback()( newval );
271+ }
117272 }
273+ else if constexpr ( is_vector <decltype(real_container)>::value )
274+ {
275+ bool replaced = real_container.ReplaceValues( oldval, newval );
276+
277+ if ( replaced )
278+ {
279+ container.GetRemoveCallback()( oldval );
280+ container.GetAddCallback()( newval );
281+ }
282+ }
283+ else if constexpr (
284+ EqualityComparableValues <findItemType, decltype(real_container)> &&
285+ std::is_assignable <decltype(real_container), putItemType>::value
286+ )
287+ {
288+ if ( real_container == oldval )
289+ {
290+ container.GetRemoveCallback()( real_container );
291+
292+ real_container = std::forward <putItemType> ( newval );
293+
294+ container.GetAddCallback()( real_container );
295+ }
296+ }
297+ else
298+ {
299+ bool replaced = false;
300+
301+ for ( auto& ival : real_container )
302+ {
303+ if ( ival == oldval )
304+ {
305+ ival = newval;
306+
307+ replaced = true;
308+ }
309+ }
310+
311+ if ( replaced )
312+ {
313+ container.GetRemoveCallback()( oldval );
314+ container.GetAddCallback()( newval );
315+ }
316+ }
118317 }
119318 else
120319 {
121- for ( auto& ival : container )
320+ if constexpr ( is_set <decltype(container)>::value )
122321 {
123- if ( ival == oldval )
322+ if ( auto *foundNode = container.Find( oldval ) )
124323 {
125- ival = newval;
324+ auto& upd = container.BeginNodeUpdate( foundNode );
325+
326+ upd = std::forward <putItemType> ( newval );
327+
328+ container.EndNodeUpdate( foundNode );
126329 }
127330 }
331+ else if constexpr ( is_multivaluestore <decltype(container)>::value )
332+ {
333+ container.Replace( oldval, std::forward <putItemType> ( newval ) );
334+ }
335+ // if eir::Vector, then (we could just) fall-through to default handler.
336+ else if constexpr ( is_vector <decltype(container)>::value )
337+ {
338+ container.ReplaceValues( oldval, std::forward <putItemType> ( newval ) );
339+ }
340+ else if constexpr (
341+ EqualityComparableValues <findItemType, decltype(container)> &&
342+ std::is_assignable <decltype(container), putItemType>::value
343+ )
344+ {
345+ if ( container == oldval )
346+ {
347+ container = std::forward <putItemType> ( newval );
348+ }
349+ }
350+ else
351+ {
352+ for ( auto& ival : container )
353+ {
354+ if ( ival == oldval )
355+ {
356+ ival = newval;
357+ }
358+ }
359+ }
128360 }
129361 };
130362
@@ -131,6 +363,7 @@
131363 ( _replace_lambda( containers ), ... );
132364 }
133365
366+// The word "unique" here is actually redundant.
134367 enum class eUniqueVectorRemovalPolicy
135368 {
136369 REMOVE,
@@ -143,35 +376,103 @@
143376 {
144377 auto _remove_lambda = [&]( auto& container ) LAINLINE
145378 {
146- if constexpr ( is_set <decltype(container)>::value )
379+ // Code-path splicing necessary for the same reason as in replaceInContainer.
380+ if constexpr ( is_contain_notify_add_remove_tie <decltype(container)>::value || is_contain_notify_remove_tie <decltype(container)>::value )
147381 {
148- container.Remove( findval );
149- }
150- else if constexpr ( is_multivaluestore <decltype(container)>::value )
151- {
152- container.RemoveAll( findval );
153- }
154- else if constexpr ( is_vector <decltype(container)>::value && vecRemPolicy == eUniqueVectorRemovalPolicy::REMOVE )
155- {
156- // If the policy is not equal to REMOVE, then we fall down to the replacement logic below.
157- container.RemoveByValue( findval );
158- }
159- else if constexpr ( std::same_as <decltype(container), itemType&> )
160- {
161- if ( findval != itemType() && container == findval )
382+ auto& real_container = container.GetContainer();
383+
384+ if constexpr ( is_set <decltype(real_container)>::value )
162385 {
163- container = {};
386+ if ( auto *findNode = real_container.Find( findval ) )
387+ {
388+ container.GetRemoveCallback()( findNode->GetValue() );
389+
390+ real_container.RemoveNode( findNode );
391+ }
164392 }
393+ else if constexpr ( is_multivaluestore <decltype(real_container)>::value )
394+ {
395+ bool removed = real_container.RemoveAll( findval );
396+
397+ if ( removed )
398+ {
399+ container.GetRemoveCallback()( findval );
400+ }
401+ }
402+ else if constexpr ( is_vector <decltype(real_container)>::value && vecRemPolicy == eUniqueVectorRemovalPolicy::REMOVE )
403+ {
404+ // If the policy is not equal to REMOVE, then we fall down to the replacement logic below.
405+ bool removed = real_container.RemoveByValue( findval );
406+
407+ if ( removed )
408+ {
409+ container.GetRemoveCallback()( findval );
410+ }
411+ }
412+ else if constexpr ( std::same_as <decltype(real_container), itemType&> )
413+ {
414+ if ( findval != itemType() && real_container == findval )
415+ {
416+ container.GetRemoveCallback()( real_container );
417+
418+ real_container = {};
419+ }
420+ }
421+ else
422+ {
423+ if ( findval != itemType() )
424+ {
425+ bool didRemove = false;
426+
427+ for ( auto& ival : real_container )
428+ {
429+ if ( ival == findval )
430+ {
431+ ival = {};
432+
433+ didRemove = true;
434+ }
435+ }
436+
437+ if ( didRemove )
438+ {
439+ container.GetRemoveCallback()( findval );
440+ }
441+ }
442+ }
165443 }
166444 else
167445 {
168- if ( findval != itemType() )
446+ if constexpr ( is_set <decltype(container)>::value )
169447 {
170- for ( auto& ival : container )
448+ container.Remove( findval );
449+ }
450+ else if constexpr ( is_multivaluestore <decltype(container)>::value )
451+ {
452+ container.RemoveAll( findval );
453+ }
454+ else if constexpr ( is_vector <decltype(container)>::value && vecRemPolicy == eUniqueVectorRemovalPolicy::REMOVE )
455+ {
456+ // If the policy is not equal to REMOVE, then we fall down to the replacement logic below.
457+ container.RemoveByValue( findval );
458+ }
459+ else if constexpr ( std::same_as <decltype(container), itemType&> )
460+ {
461+ if ( findval != itemType() && container == findval )
171462 {
172- if ( ival == findval )
463+ container = {};
464+ }
465+ }
466+ else
467+ {
468+ if ( findval != itemType() )
469+ {
470+ for ( auto& ival : container )
173471 {
174- ival = {};
472+ if ( ival == findval )
473+ {
474+ ival = {};
475+ }
175476 }
176477 }
177478 }
--- common/sdk/MultiValueStore.h (revision 458)
+++ common/sdk/MultiValueStore.h (revision 459)
@@ -71,14 +71,14 @@
7171 }
7272 }
7373
74- // Removes a single instance of the given value.
74+ // Removes a single instance of the given value. Returns true if successful.
7575 template <ThreeWayComparableValues <valueType> queryType>
76- inline void Remove( const queryType& value )
76+ inline bool Remove( const queryType& value )
7777 {
7878 auto *findNode = this->valrefs.Find( value );
7979
8080 if ( findNode == nullptr )
81- return;
81+ return false;
8282
8383 const valinfo& info = findNode->GetValue();
8484
@@ -92,16 +92,19 @@
9292 {
9393 this->valrefs.RemoveNode( findNode );
9494 }
95+ return true;
9596 }
9697 // Removes all instances of the given value.
9798 template <ThreeWayComparableValues <valueType> queryType>
98- inline void RemoveAll( const queryType& value )
99+ inline bool RemoveAll( const queryType& value )
99100 {
100- this->valrefs.Remove( value );
101+ return this->valrefs.Remove( value );
101102 }
102103
104+ // Returns true if the replacement was successfully performed, hence findval has existed and was replaced with
105+ // replaceby.
103106 template <ThreeWayComparableValues <valueType> queryType, std::convertible_to <valueType> convValueType>
104- inline void Replace( const queryType& findval, convValueType&& replaceby )
107+ inline bool Replace( const queryType& findval, convValueType&& replaceby )
105108 {
106109 if ( auto *findNode = this->valrefs.Find( findval ) )
107110 {
@@ -121,7 +124,9 @@
121124
122125 this->valrefs.EndNodeUpdate( findNode );
123126 }
127+ return true;
124128 }
129+ return false;
125130 }
126131
127132 inline size_t GetValueCount( void ) const noexcept
--- common/sdk/Set.h (revision 458)
+++ common/sdk/Set.h (revision 459)
@@ -414,17 +414,19 @@
414414
415415 // Erases any Node by value.
416416 template <typename queryType> requires ( CompareCompatibleComparator <comparatorType, valueType, queryType> )
417- inline void Remove( const queryType& value ) noexcept(NothrowCompareCompatibleComparator <comparatorType, valueType, queryType>)
417+ inline bool Remove( const queryType& value ) noexcept(NothrowCompareCompatibleComparator <comparatorType, valueType, queryType>)
418418 {
419419 AVLNode *avlExistingNode = this->data.avlValueTree.FindNode( value );
420420
421421 if ( avlExistingNode == nullptr )
422- return;
422+ return false;
423423
424424 // Remove it.
425425 Node *existingNode = AVL_GETITEM( Node, avlExistingNode, sortedByValueNode );
426426
427427 RemoveNode( existingNode );
428+
429+ return true;
428430 }
429431
430432 // Clears all values from this Set.
--- common/sdk/UniqueIterate.h (revision 458)
+++ common/sdk/UniqueIterate.h (revision 459)
@@ -143,7 +143,7 @@
143143
144144 template <typename itemType, typename optionalStore = std::optional <itemType>, typename... containerTypes, typename... excludeContainerTypes>
145145 requires ( sizeof...( containerTypes ) > 0 )
146-AINLINE optionalStore uniqueFetchNextTuple( typename std::common_type <optionalStore>::type prev, const std::tuple <containerTypes...>& containers, const std::tuple <excludeContainerTypes...>& exclude_containers = std::tuple() )
146+AINLINE optionalStore uniqueFetchNextTuple( typename std::type_identity <optionalStore>::type prev, const std::tuple <containerTypes...>& containers, const std::tuple <excludeContainerTypes...>& exclude_containers = std::tuple() )
147147 {
148148 size_t container_idx = 0;
149149
@@ -266,7 +266,7 @@
266266
267267 template <typename itemType, typename optionalStore = std::optional <itemType>, typename... containerTypes>
268268 requires ( sizeof...( containerTypes ) > 0 )
269-AINLINE optionalStore uniqueFetchNext( typename std::common_type <optionalStore>::type prev, const containerTypes&... containers )
269+AINLINE optionalStore uniqueFetchNext( typename std::type_identity <optionalStore>::type prev, const containerTypes&... containers )
270270 {
271271 return uniqueFetchNextTuple <itemType, optionalStore> ( std::forward <optionalStore> ( prev ), std::tuple <const containerTypes&...> ( containers... ) );
272272 }
--- common/sdk/Vector.h (revision 458)
+++ common/sdk/Vector.h (revision 459)
@@ -1037,9 +1037,9 @@
10371037 }
10381038 }
10391039 }
1040- // Replaces all entries of equal value in this vector.
1040+ // Replaces all entries of equal value in this vector. Returns true if any replacement was performed successfully.
10411041 template <EqualityComparableValues <structType> queryType, std::convertible_to <structType> replType> requires ( Vectorable <structType> )
1042- inline void ReplaceValues( const queryType& find, replType&& replace_with )
1042+ inline bool ReplaceValues( const queryType& find, replType&& replace_with )
10431043 {
10441044 size_t cnt = this->data.data_count;
10451045 structType *dataptr = this->data.data_entries;
@@ -1046,6 +1046,8 @@
10461046
10471047 structType *prev_item = nullptr;
10481048
1049+ bool didReplace = false;
1050+
10491051 for ( size_t n = 0; n < cnt; n++ )
10501052 {
10511053 structType& entry = dataptr[ n ];
@@ -1058,13 +1060,19 @@
10581060 }
10591061
10601062 prev_item = &entry;
1063+
1064+ didReplace = true;
10611065 }
10621066 }
10631067
10641068 if ( prev_item )
10651069 {
1066- *prev_item = std::move( replace_with );
1070+ *prev_item = std::forward <replType> ( replace_with );
1071+
1072+ didReplace = true;
10671073 }
1074+
1075+ return didReplace;
10681076 }
10691077
10701078 // Writes the contents of one array into this array at a certain offset.
@@ -1215,11 +1223,13 @@
12151223
12161224 // Easy helper to remove all items of a certain value.
12171225 template <EqualityComparableValues <structType> cmpValueType> requires ( Vectorable <structType> )
1218- inline void RemoveByValue( const cmpValueType& theValue )
1226+ inline bool RemoveByValue( const cmpValueType& theValue )
12191227 {
12201228 size_t curCount = this->data.data_count;
12211229 size_t cur_idx = 0;
12221230
1231+ bool removed = false;
1232+
12231233 while ( cur_idx < curCount )
12241234 {
12251235 bool removeCurrent = false;
@@ -1236,6 +1246,8 @@
12361246 {
12371247 this->RemoveByIndex( cur_idx );
12381248
1249+ removed = true;
1250+
12391251 curCount--;
12401252 }
12411253 else
@@ -1243,6 +1255,8 @@
12431255 cur_idx++;
12441256 }
12451257 }
1258+
1259+ return removed;
12461260 }
12471261
12481262 // Returns a reference to a slot on this vector. If indices up to and including this
--- unittests/src/iterate.cpp (revision 458)
+++ unittests/src/iterate.cpp (revision 459)
@@ -261,4 +261,230 @@
261261 assert( vec[2] == 3 );
262262 }
263263 printf( "ok.\n" );
264+
265+ printf( "testing containNotifyAddRemoveTie construction..." );
266+ {
267+ int i = 52;
268+
269+ eir::containNotifyAddRemoveTie tie( i, []( int ){}, []( int ){} );
270+
271+ static_assert( decltype(tie)::is_about <int>::value == true );
272+ }
273+ printf( "ok.\n" );
274+
275+ printf( "testing containNotifyAddRemoveTie as pass-through... ");
276+ {
277+ int i = 42;
278+
279+ eir::containNotifyAddRemoveTie tie( i, []( int ){}, []( int ){} );
280+
281+ int val = std::move( tie );
282+
283+ assert( val == 42 );
284+ }
285+ printf( "ok.\n" );
286+
287+ printf( "testing containNotifyRemoveTie construction..." );
288+ {
289+ int i = 52;
290+
291+ eir::containNotifyRemoveTie tie( i, []( int ){} );
292+
293+ static_assert( decltype(tie)::is_about <int>::value == true );
294+ }
295+ printf( "ok.\n" );
296+
297+ printf( "testing containNotifyRemoveTie as pass-through... ");
298+ {
299+ int i = 42;
300+
301+ eir::containNotifyRemoveTie tie( i, []( int ){} );
302+
303+ int val = std::move( tie );
304+
305+ assert( val == 42 );
306+ }
307+ printf( "ok.\n" );
308+
309+ printf( "testing replaceInContainer (with containNotifyAddRemoveTie)..." );
310+ {
311+ static bool has_vec_added = false;
312+ static bool has_vec_removed = false;
313+ static bool has_set_added = false;
314+ static bool has_set_removed = false;
315+ static bool has_field_added = false;
316+ static bool has_field_removed = false;
317+ static bool has_mvs_added = false;
318+ static bool has_mvs_removed = false;
319+
320+ auto on_vec_add = []( const int& val )
321+ {
322+ assert( val == 42 );
323+
324+ has_vec_added = true;
325+ };
326+ auto on_vec_remove = []( const int& val )
327+ {
328+ assert( val == 1 );
329+
330+ has_vec_removed = true;
331+ };
332+ auto on_set_add = []( const int& val )
333+ {
334+ assert( val == 42 );
335+
336+ has_set_added = true;
337+ };
338+ auto on_set_remove = []( const int& val )
339+ {
340+ assert( val == 4 );
341+
342+ has_set_removed = true;
343+ };
344+ auto on_field_add = []( const int& val )
345+ {
346+ assert( val == 42 );
347+
348+ has_field_added = true;
349+ };
350+ auto on_field_remove = []( const int& val )
351+ {
352+ assert( val == 7 );
353+
354+ has_field_removed = true;
355+ };
356+ auto on_mvs_add = []( const int& val )
357+ {
358+ assert( val == 42 );
359+
360+ has_mvs_added = true;
361+ };
362+ auto on_mvs_remove = []( const int& val )
363+ {
364+ assert( val == 8 );
365+
366+ has_mvs_removed = true;
367+ };
368+
369+ eir::Vector <int, CRTHeapAllocator> vec = std::array{ 1, 2, 3 };
370+ eir::Set <int, CRTHeapAllocator> set = std::array{ 4, 5, 6 };
371+ int field = 7;
372+ eir::MultiValueStore <int, CRTHeapAllocator> mvs = std::array{ 8, 9, 10 };
373+
374+ eir::replaceInContainer( 1, 42,
375+ eir::containNotifyAddRemoveTie( vec, on_vec_add, on_vec_remove ),
376+ eir::containNotifyAddRemoveTie( set, on_set_add, on_set_remove ),
377+ eir::containNotifyAddRemoveTie( field, on_field_add, on_field_remove ),
378+ eir::containNotifyAddRemoveTie( mvs, on_mvs_add, on_mvs_remove )
379+ );
380+
381+ assert( has_vec_removed == true );
382+ assert( has_vec_added == true );
383+
384+ eir::replaceInContainer( 4, 42,
385+ eir::containNotifyAddRemoveTie( vec, on_vec_add, on_vec_remove ),
386+ eir::containNotifyAddRemoveTie( set, on_set_add, on_set_remove ),
387+ eir::containNotifyAddRemoveTie( field, on_field_add, on_field_remove ),
388+ eir::containNotifyAddRemoveTie( mvs, on_mvs_add, on_mvs_remove )
389+ );
390+
391+ assert( has_set_added == true );
392+ assert( has_set_removed == true );
393+
394+ eir::replaceInContainer( 7, 42,
395+ eir::containNotifyAddRemoveTie( vec, on_vec_add, on_vec_remove ),
396+ eir::containNotifyAddRemoveTie( set, on_set_add, on_set_remove ),
397+ eir::containNotifyAddRemoveTie( field, on_field_add, on_field_remove ),
398+ eir::containNotifyAddRemoveTie( mvs, on_mvs_add, on_mvs_remove )
399+ );
400+
401+ assert( has_field_added == true );
402+ assert( has_field_removed == true );
403+
404+ eir::replaceInContainer( 8, 42,
405+ eir::containNotifyAddRemoveTie( vec, on_vec_add, on_vec_remove ),
406+ eir::containNotifyAddRemoveTie( set, on_set_add, on_set_remove ),
407+ eir::containNotifyAddRemoveTie( field, on_field_add, on_field_remove ),
408+ eir::containNotifyAddRemoveTie( mvs, on_mvs_add, on_mvs_remove )
409+ );
410+
411+ assert( has_mvs_added == true );
412+ assert( has_mvs_removed == true );
413+ }
414+ printf( "ok.\n" );
415+
416+ printf( "testing removeFromContainer (with containNotifyRemoveTie)..." );
417+ {
418+ static bool has_vec_removed = false;
419+ static bool has_set_removed = false;
420+ static bool has_field_removed = false;
421+ static bool has_mvs_removed = false;
422+
423+ auto on_vec_remove = []( const int& val )
424+ {
425+ assert( val == 1 );
426+
427+ has_vec_removed = true;
428+ };
429+ auto on_set_remove = []( const int& val )
430+ {
431+ assert( val == 4 );
432+
433+ has_set_removed = true;
434+ };
435+ auto on_field_remove = []( const int& val )
436+ {
437+ assert( val == 7 );
438+
439+ has_field_removed = true;
440+ };
441+ auto on_mvs_remove = []( const int& val )
442+ {
443+ assert( val == 8 );
444+
445+ has_mvs_removed = true;
446+ };
447+
448+ eir::Vector <int, CRTHeapAllocator> vec = std::array{ 1, 2, 3 };
449+ eir::Set <int, CRTHeapAllocator> set = std::array{ 4, 5, 6 };
450+ int field = 7;
451+ eir::MultiValueStore <int, CRTHeapAllocator> mvs = std::array{ 8, 9, 10 };
452+
453+ eir::removeFromContainer( 1,
454+ eir::containNotifyRemoveTie( vec, on_vec_remove ),
455+ eir::containNotifyRemoveTie( set, on_set_remove ),
456+ eir::containNotifyRemoveTie( field, on_field_remove ),
457+ eir::containNotifyRemoveTie( mvs, on_mvs_remove )
458+ );
459+
460+ assert( has_vec_removed == true );
461+
462+ eir::removeFromContainer( 4,
463+ eir::containNotifyRemoveTie( vec, on_vec_remove ),
464+ eir::containNotifyRemoveTie( set, on_set_remove ),
465+ eir::containNotifyRemoveTie( field, on_field_remove ),
466+ eir::containNotifyRemoveTie( mvs, on_mvs_remove )
467+ );
468+
469+ assert( has_set_removed == true );
470+
471+ eir::removeFromContainer( 7,
472+ eir::containNotifyRemoveTie( vec, on_vec_remove ),
473+ eir::containNotifyRemoveTie( set, on_set_remove ),
474+ eir::containNotifyRemoveTie( field, on_field_remove ),
475+ eir::containNotifyRemoveTie( mvs, on_mvs_remove )
476+ );
477+
478+ assert( has_field_removed == true );
479+
480+ eir::removeFromContainer( 8,
481+ eir::containNotifyRemoveTie( vec, on_vec_remove ),
482+ eir::containNotifyRemoveTie( set, on_set_remove ),
483+ eir::containNotifyRemoveTie( field, on_field_remove ),
484+ eir::containNotifyRemoveTie( mvs, on_mvs_remove )
485+ );
486+
487+ assert( has_mvs_removed == true );
488+ }
489+ printf( "ok.\n" );
264490 }
\ No newline at end of file
Show on old repository browser