@@ -44,6 +44,12 @@ Author: Daniel Poetzl
44
44
template <class keyT , class valueT , class hashT , class equalT > \
45
45
CV typename sharing_mapt<keyT, valueT, hashT, equalT>::ST \
46
46
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>
47
53
// clang-format on
48
54
49
55
// Note: Due to a bug in Visual Studio we need to add an additional "const"
@@ -128,6 +134,7 @@ class sharing_mapt
128
134
friend void sharing_map_copy_test ();
129
135
friend void sharing_map_collision_test ();
130
136
friend void sharing_map_view_test ();
137
+ friend void sharing_map_sharing_stats_test ();
131
138
132
139
~sharing_mapt ()
133
140
{
@@ -291,6 +298,36 @@ class sharing_mapt
291
298
delta_viewt &delta_view,
292
299
const bool only_common = true ) const ;
293
300
301
+ // / Stats about sharing between several sharing map instances. An instance of
302
+ // / this class is returned by the get_sharing_map_stats_* functions.
303
+ // /
304
+ // / The num_nodes field gives the total number of nodes in the given maps.
305
+ // / Nodes that are part of n of the maps are counted n times.
306
+ // /
307
+ // / The num_unique_nodes field gives the number of unique nodes in the given
308
+ // / maps. A node that is part of several of the maps is only counted once.
309
+ // /
310
+ // / The num_leafs and num_unique_leafs fields are similar to the above but
311
+ // / only leafs are counted.
312
+ class sharing_map_statst
313
+ {
314
+ public:
315
+ std::size_t num_nodes = 0 ;
316
+ std::size_t num_unique_nodes = 0 ;
317
+ std::size_t num_leafs = 0 ;
318
+ std::size_t num_unique_leafs = 0 ;
319
+ };
320
+
321
+ template <class Iterator >
322
+ static sharing_map_statst get_sharing_stats (
323
+ Iterator begin,
324
+ Iterator end,
325
+ std::function<sharing_mapt &(const Iterator)> f =
326
+ [](const Iterator it) -> sharing_mapt & { return *it; });
327
+
328
+ template <class Iterator >
329
+ static sharing_map_statst get_sharing_stats_map (Iterator begin, Iterator end);
330
+
294
331
protected:
295
332
// helpers
296
333
@@ -317,6 +354,11 @@ class sharing_mapt
317
354
void gather_all (const baset &n, const unsigned depth, delta_viewt &delta_view)
318
355
const ;
319
356
357
+ std::size_t count_unmarked_nodes (
358
+ bool leafs_only,
359
+ std::set<void *> &marked,
360
+ bool mark = true ) const ;
361
+
320
362
// dummy element returned when no element was found
321
363
static mapped_type dummy;
322
364
@@ -386,6 +428,167 @@ ::iterate(
386
428
while (!stack.empty ());
387
429
}
388
430
431
+ SHARING_MAPT (std::size_t )
432
+ ::count_unmarked_nodes(bool leafs_only, std::set<void *> &marked, bool mark)
433
+ const
434
+ {
435
+ if (empty ())
436
+ return 0 ;
437
+
438
+ unsigned count = 0 ;
439
+
440
+ typedef std::pair<unsigned , const baset *> stack_itemt;
441
+
442
+ std::stack<stack_itemt> stack;
443
+ stack.push ({0 , &map});
444
+
445
+ do
446
+ {
447
+ const stack_itemt &si = stack.top ();
448
+
449
+ const unsigned depth = si.first ;
450
+ const baset *bp = si.second ;
451
+
452
+ stack.pop ();
453
+
454
+ // internal node or container node
455
+ const innert *ip = static_cast <const innert *>(bp);
456
+ const unsigned use_count = ip->data .use_count ();
457
+ void *raw_ptr = ip->data .get ();
458
+
459
+ if (use_count >= 2 )
460
+ {
461
+ if (marked.find (raw_ptr) != marked.end ())
462
+ {
463
+ continue ;
464
+ }
465
+
466
+ if (mark)
467
+ {
468
+ marked.insert (raw_ptr);
469
+ }
470
+ }
471
+
472
+ if (!leafs_only)
473
+ {
474
+ count++;
475
+ }
476
+
477
+ if (depth < steps) // internal
478
+ {
479
+ const to_mapt &m = ip->get_to_map ();
480
+ SM_ASSERT (!m.empty ());
481
+
482
+ for (const auto &item : m)
483
+ {
484
+ const innert *i = &item.second ;
485
+ stack.push ({depth + 1 , i});
486
+ }
487
+ }
488
+ else // container
489
+ {
490
+ SM_ASSERT (depth == steps);
491
+
492
+ const leaf_listt &ll = ip->get_container ();
493
+ SM_ASSERT (!ll.empty ());
494
+
495
+ for (const auto &l : ll)
496
+ {
497
+ const unsigned use_count = l.data .use_count ();
498
+ void *raw_ptr = l.data .get ();
499
+
500
+ if (use_count >= 2 )
501
+ {
502
+ if (marked.find (raw_ptr) != marked.end ())
503
+ {
504
+ continue ;
505
+ }
506
+
507
+ if (mark)
508
+ {
509
+ marked.insert (raw_ptr);
510
+ }
511
+ }
512
+
513
+ count++;
514
+ }
515
+ }
516
+ } while (!stack.empty ());
517
+
518
+ return count;
519
+ }
520
+
521
+ // / Get sharing stats
522
+ // /
523
+ // / Complexity:
524
+ // / - Worst case: O(N * H * log(S))
525
+ // / - Best case: O(N + H)
526
+ // /
527
+ // / \param begin: begin iterator
528
+ // / \param end: end iterator
529
+ // / \param f: function applied to the iterator to get a sharing map
530
+ // / \return: sharing stats
531
+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
532
+ ::get_sharing_stats(
533
+ Iterator begin,
534
+ Iterator end,
535
+ std::function<sharing_mapt &(const Iterator)> f)
536
+ {
537
+ std::set<void *> marked;
538
+ sharing_map_statst sms;
539
+
540
+ // We do a separate pass over the tree for each statistic. This is not very
541
+ // efficient but the function is intended only for diagnosis purposes anyways.
542
+
543
+ // number of nodes
544
+ for (Iterator it = begin; it != end; it++)
545
+ {
546
+ sms.num_nodes += f (it).count_unmarked_nodes (false , marked, false );
547
+ }
548
+
549
+ SM_ASSERT (marked.empty ());
550
+
551
+ // number of unique nodes
552
+ for (Iterator it = begin; it != end; it++)
553
+ {
554
+ sms.num_unique_nodes += f (it).count_unmarked_nodes (false , marked, true );
555
+ }
556
+
557
+ marked.clear ();
558
+
559
+ // number of leafs
560
+ for (Iterator it = begin; it != end; it++)
561
+ {
562
+ sms.num_leafs += f (it).count_unmarked_nodes (true , marked, false );
563
+ }
564
+
565
+ SM_ASSERT (marked.empty ());
566
+
567
+ // number of unique leafs
568
+ for (Iterator it = begin; it != end; it++)
569
+ {
570
+ sms.num_unique_leafs += f (it).count_unmarked_nodes (true , marked, true );
571
+ }
572
+
573
+ return sms;
574
+ }
575
+
576
+ // / Get sharing stats
577
+ // /
578
+ // / Complexity:
579
+ // / - Worst case: O(N * H * log(S))
580
+ // / - Best case: O(N + H)
581
+ // /
582
+ // / \param begin: begin iterator of a map
583
+ // / \param end: end iterator of a map
584
+ // / \return: sharing stats
585
+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
586
+ ::get_sharing_stats_map(Iterator begin, Iterator end)
587
+ {
588
+ return get_sharing_stats<Iterator>(
589
+ begin, end, [](const Iterator it) -> sharing_mapt & { return it->second ; });
590
+ }
591
+
389
592
// / Get a view of the elements in the map
390
593
// / A view is a list of pairs with the components being const references to the
391
594
// / keys and values in the map.
0 commit comments