@@ -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,35 @@ 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
+ struct sharing_map_statst
313
+ {
314
+ std::size_t num_nodes = 0 ;
315
+ std::size_t num_unique_nodes = 0 ;
316
+ std::size_t num_leafs = 0 ;
317
+ std::size_t num_unique_leafs = 0 ;
318
+ };
319
+
320
+ template <class Iterator >
321
+ static sharing_map_statst get_sharing_stats (
322
+ Iterator begin,
323
+ Iterator end,
324
+ std::function<sharing_mapt &(const Iterator)> f =
325
+ [](const Iterator it) -> sharing_mapt & { return *it; });
326
+
327
+ template <class Iterator >
328
+ static sharing_map_statst get_sharing_stats_map (Iterator begin, Iterator end);
329
+
294
330
protected:
295
331
// helpers
296
332
@@ -317,6 +353,11 @@ class sharing_mapt
317
353
void gather_all (const baset &n, const unsigned depth, delta_viewt &delta_view)
318
354
const ;
319
355
356
+ std::size_t count_unmarked_nodes (
357
+ bool leafs_only,
358
+ std::set<void *> &marked,
359
+ bool mark = true ) const ;
360
+
320
361
// dummy element returned when no element was found
321
362
static mapped_type dummy;
322
363
@@ -386,6 +427,167 @@ ::iterate(
386
427
while (!stack.empty ());
387
428
}
388
429
430
+ SHARING_MAPT (std::size_t )
431
+ ::count_unmarked_nodes(bool leafs_only, std::set<void *> &marked, bool mark)
432
+ const
433
+ {
434
+ if (empty ())
435
+ return 0 ;
436
+
437
+ unsigned count = 0 ;
438
+
439
+ typedef std::pair<unsigned , const baset *> stack_itemt;
440
+
441
+ std::stack<stack_itemt> stack;
442
+ stack.push ({0 , &map});
443
+
444
+ do
445
+ {
446
+ const stack_itemt &si = stack.top ();
447
+
448
+ const unsigned depth = si.first ;
449
+ const baset *bp = si.second ;
450
+
451
+ stack.pop ();
452
+
453
+ // internal node or container node
454
+ const innert *ip = static_cast <const innert *>(bp);
455
+ const unsigned use_count = ip->data .use_count ();
456
+ void *raw_ptr = ip->data .get ();
457
+
458
+ if (use_count >= 2 )
459
+ {
460
+ if (marked.find (raw_ptr) != marked.end ())
461
+ {
462
+ continue ;
463
+ }
464
+
465
+ if (mark)
466
+ {
467
+ marked.insert (raw_ptr);
468
+ }
469
+ }
470
+
471
+ if (!leafs_only)
472
+ {
473
+ count++;
474
+ }
475
+
476
+ if (depth < steps) // internal
477
+ {
478
+ const to_mapt &m = ip->get_to_map ();
479
+ SM_ASSERT (!m.empty ());
480
+
481
+ for (const auto &item : m)
482
+ {
483
+ const innert *i = &item.second ;
484
+ stack.push ({depth + 1 , i});
485
+ }
486
+ }
487
+ else // container
488
+ {
489
+ SM_ASSERT (depth == steps);
490
+
491
+ const leaf_listt &ll = ip->get_container ();
492
+ SM_ASSERT (!ll.empty ());
493
+
494
+ for (const auto &l : ll)
495
+ {
496
+ const unsigned use_count = l.data .use_count ();
497
+ void *raw_ptr = l.data .get ();
498
+
499
+ if (use_count >= 2 )
500
+ {
501
+ if (marked.find (raw_ptr) != marked.end ())
502
+ {
503
+ continue ;
504
+ }
505
+
506
+ if (mark)
507
+ {
508
+ marked.insert (raw_ptr);
509
+ }
510
+ }
511
+
512
+ count++;
513
+ }
514
+ }
515
+ } while (!stack.empty ());
516
+
517
+ return count;
518
+ }
519
+
520
+ // / Get sharing stats
521
+ // /
522
+ // / Complexity:
523
+ // / - Worst case: O(N * H * log(S))
524
+ // / - Best case: O(N + H)
525
+ // /
526
+ // / \param begin: begin iterator
527
+ // / \param end: end iterator
528
+ // / \param f: function applied to the iterator to get a sharing map
529
+ // / \return: sharing stats
530
+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
531
+ ::get_sharing_stats(
532
+ Iterator begin,
533
+ Iterator end,
534
+ std::function<sharing_mapt &(const Iterator)> f)
535
+ {
536
+ std::set<void *> marked;
537
+ sharing_map_statst sms;
538
+
539
+ // We do a separate pass over the tree for each statistic. This is not very
540
+ // efficient but the function is intended only for diagnosis purposes anyways.
541
+
542
+ // number of nodes
543
+ for (Iterator it = begin; it != end; it++)
544
+ {
545
+ sms.num_nodes += f (it).count_unmarked_nodes (false , marked, false );
546
+ }
547
+
548
+ SM_ASSERT (marked.empty ());
549
+
550
+ // number of unique nodes
551
+ for (Iterator it = begin; it != end; it++)
552
+ {
553
+ sms.num_unique_nodes += f (it).count_unmarked_nodes (false , marked, true );
554
+ }
555
+
556
+ marked.clear ();
557
+
558
+ // number of leafs
559
+ for (Iterator it = begin; it != end; it++)
560
+ {
561
+ sms.num_leafs += f (it).count_unmarked_nodes (true , marked, false );
562
+ }
563
+
564
+ SM_ASSERT (marked.empty ());
565
+
566
+ // number of unique leafs
567
+ for (Iterator it = begin; it != end; it++)
568
+ {
569
+ sms.num_unique_leafs += f (it).count_unmarked_nodes (true , marked, true );
570
+ }
571
+
572
+ return sms;
573
+ }
574
+
575
+ // / Get sharing stats
576
+ // /
577
+ // / Complexity:
578
+ // / - Worst case: O(N * H * log(S))
579
+ // / - Best case: O(N + H)
580
+ // /
581
+ // / \param begin: begin iterator of a map
582
+ // / \param end: end iterator of a map
583
+ // / \return: sharing stats
584
+ SHARING_MAPT3 (Iterator, , sharing_map_statst)
585
+ ::get_sharing_stats_map(Iterator begin, Iterator end)
586
+ {
587
+ return get_sharing_stats<Iterator>(
588
+ begin, end, [](const Iterator it) -> sharing_mapt & { return it->second ; });
589
+ }
590
+
389
591
// / Get a view of the elements in the map
390
592
// / A view is a list of pairs with the components being const references to the
391
593
// / keys and values in the map.
0 commit comments