@@ -44,6 +44,12 @@ Author: Daniel Poetzl
4444 template <class keyT , class valueT , class hashT , class equalT > \
4545 CV typename sharing_mapt<keyT, valueT, hashT, equalT>::ST \
4646 sharing_mapt<keyT, valueT, hashT, equalT>
47+
48+ #define SHARING_MAPT3 (T, CV, ST ) \
49+ template <class keyT , class valueT , class hashT , class equalT > \
50+ template <class T > \
51+ CV typename sharing_mapt<keyT, valueT, hashT, equalT>::ST \
52+ sharing_mapt<keyT, valueT, hashT, equalT>
4753// clang-format on
4854
4955// Note: Due to a bug in Visual Studio we need to add an additional "const"
@@ -124,11 +130,6 @@ template <class keyT,
124130class sharing_mapt
125131{
126132public:
127- friend void sharing_map_interface_test ();
128- friend void sharing_map_copy_test ();
129- friend void sharing_map_collision_test ();
130- friend void sharing_map_view_test ();
131-
132133 ~sharing_mapt ()
133134 {
134135 }
@@ -291,6 +292,35 @@ class sharing_mapt
291292 delta_viewt &delta_view,
292293 const bool only_common = true ) const ;
293294
295+ // / Stats about sharing between several sharing map instances. An instance of
296+ // / this class is returned by the get_sharing_map_stats_* functions.
297+ // /
298+ // / The num_nodes field gives the total number of nodes in the given maps.
299+ // / Nodes that are part of n of the maps are counted n times.
300+ // /
301+ // / The num_unique_nodes field gives the number of unique nodes in the given
302+ // / maps. A node that is part of several of the maps is only counted once.
303+ // /
304+ // / The num_leafs and num_unique_leafs fields are similar to the above but
305+ // / only leafs are counted.
306+ struct sharing_map_statst
307+ {
308+ std::size_t num_nodes = 0 ;
309+ std::size_t num_unique_nodes = 0 ;
310+ std::size_t num_leafs = 0 ;
311+ std::size_t num_unique_leafs = 0 ;
312+ };
313+
314+ template <class Iterator >
315+ static sharing_map_statst get_sharing_stats (
316+ Iterator begin,
317+ Iterator end,
318+ std::function<sharing_mapt &(const Iterator)> f =
319+ [](const Iterator it) -> sharing_mapt & { return *it; });
320+
321+ template <class Iterator >
322+ static sharing_map_statst get_sharing_stats_map (Iterator begin, Iterator end);
323+
294324protected:
295325 // helpers
296326
@@ -317,6 +347,11 @@ class sharing_mapt
317347 void gather_all (const baset &n, const unsigned depth, delta_viewt &delta_view)
318348 const ;
319349
350+ std::size_t count_unmarked_nodes (
351+ bool leafs_only,
352+ std::set<void *> &marked,
353+ bool mark = true ) const ;
354+
320355 // dummy element returned when no element was found
321356 static mapped_type dummy;
322357
@@ -386,6 +421,167 @@ ::iterate(
386421 while (!stack.empty ());
387422}
388423
424+ SHARING_MAPT (std::size_t )
425+ ::count_unmarked_nodes(bool leafs_only, std::set<void *> &marked, bool mark)
426+ const
427+ {
428+ if (empty ())
429+ return 0 ;
430+
431+ unsigned count = 0 ;
432+
433+ typedef std::pair<unsigned , const baset *> stack_itemt;
434+
435+ std::stack<stack_itemt> stack;
436+ stack.push ({0 , &map});
437+
438+ do
439+ {
440+ const stack_itemt &si = stack.top ();
441+
442+ const unsigned depth = si.first ;
443+ const baset *bp = si.second ;
444+
445+ stack.pop ();
446+
447+ // internal node or container node
448+ const innert *ip = static_cast <const innert *>(bp);
449+ const unsigned use_count = ip->data .use_count ();
450+ void *raw_ptr = ip->data .get ();
451+
452+ if (use_count >= 2 )
453+ {
454+ if (marked.find (raw_ptr) != marked.end ())
455+ {
456+ continue ;
457+ }
458+
459+ if (mark)
460+ {
461+ marked.insert (raw_ptr);
462+ }
463+ }
464+
465+ if (!leafs_only)
466+ {
467+ count++;
468+ }
469+
470+ if (depth < steps) // internal
471+ {
472+ const to_mapt &m = ip->get_to_map ();
473+ SM_ASSERT (!m.empty ());
474+
475+ for (const auto &item : m)
476+ {
477+ const innert *i = &item.second ;
478+ stack.push ({depth + 1 , i});
479+ }
480+ }
481+ else // container
482+ {
483+ SM_ASSERT (depth == steps);
484+
485+ const leaf_listt &ll = ip->get_container ();
486+ SM_ASSERT (!ll.empty ());
487+
488+ for (const auto &l : ll)
489+ {
490+ const unsigned use_count = l.data .use_count ();
491+ void *raw_ptr = l.data .get ();
492+
493+ if (use_count >= 2 )
494+ {
495+ if (marked.find (raw_ptr) != marked.end ())
496+ {
497+ continue ;
498+ }
499+
500+ if (mark)
501+ {
502+ marked.insert (raw_ptr);
503+ }
504+ }
505+
506+ count++;
507+ }
508+ }
509+ } while (!stack.empty ());
510+
511+ return count;
512+ }
513+
514+ // / Get sharing stats
515+ // /
516+ // / Complexity:
517+ // / - Worst case: O(N * H * log(S))
518+ // / - Best case: O(N + H)
519+ // /
520+ // / \param begin: begin iterator
521+ // / \param end: end iterator
522+ // / \param f: function applied to the iterator to get a sharing map
523+ // / \return: sharing stats
524+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
525+ ::get_sharing_stats(
526+ Iterator begin,
527+ Iterator end,
528+ std::function<sharing_mapt &(const Iterator)> f)
529+ {
530+ std::set<void *> marked;
531+ sharing_map_statst sms;
532+
533+ // We do a separate pass over the tree for each statistic. This is not very
534+ // efficient but the function is intended only for diagnosis purposes anyways.
535+
536+ // number of nodes
537+ for (Iterator it = begin; it != end; it++)
538+ {
539+ sms.num_nodes += f (it).count_unmarked_nodes (false , marked, false );
540+ }
541+
542+ SM_ASSERT (marked.empty ());
543+
544+ // number of unique nodes
545+ for (Iterator it = begin; it != end; it++)
546+ {
547+ sms.num_unique_nodes += f (it).count_unmarked_nodes (false , marked, true );
548+ }
549+
550+ marked.clear ();
551+
552+ // number of leafs
553+ for (Iterator it = begin; it != end; it++)
554+ {
555+ sms.num_leafs += f (it).count_unmarked_nodes (true , marked, false );
556+ }
557+
558+ SM_ASSERT (marked.empty ());
559+
560+ // number of unique leafs
561+ for (Iterator it = begin; it != end; it++)
562+ {
563+ sms.num_unique_leafs += f (it).count_unmarked_nodes (true , marked, true );
564+ }
565+
566+ return sms;
567+ }
568+
569+ // / Get sharing stats
570+ // /
571+ // / Complexity:
572+ // / - Worst case: O(N * H * log(S))
573+ // / - Best case: O(N + H)
574+ // /
575+ // / \param begin: begin iterator of a map
576+ // / \param end: end iterator of a map
577+ // / \return: sharing stats
578+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
579+ ::get_sharing_stats_map(Iterator begin, Iterator end)
580+ {
581+ return get_sharing_stats<Iterator>(
582+ begin, end, [](const Iterator it) -> sharing_mapt & { return it->second ; });
583+ }
584+
389585// / Get a view of the elements in the map
390586// / A view is a list of pairs with the components being const references to the
391587// / keys and values in the map.
0 commit comments