@@ -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"
@@ -124,11 +130,6 @@ template <class keyT,
124
130
class sharing_mapt
125
131
{
126
132
public:
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
-
132
133
~sharing_mapt ()
133
134
{
134
135
}
@@ -291,6 +292,35 @@ class sharing_mapt
291
292
delta_viewt &delta_view,
292
293
const bool only_common = true ) const ;
293
294
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
+
294
324
protected:
295
325
// helpers
296
326
@@ -317,6 +347,11 @@ class sharing_mapt
317
347
void gather_all (const baset &n, const unsigned depth, delta_viewt &delta_view)
318
348
const ;
319
349
350
+ std::size_t count_unmarked_nodes (
351
+ bool leafs_only,
352
+ std::set<void *> &marked,
353
+ bool mark = true ) const ;
354
+
320
355
// dummy element returned when no element was found
321
356
static mapped_type dummy;
322
357
@@ -386,6 +421,167 @@ ::iterate(
386
421
while (!stack.empty ());
387
422
}
388
423
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
+
389
585
// / Get a view of the elements in the map
390
586
// / A view is a list of pairs with the components being const references to the
391
587
// / keys and values in the map.
0 commit comments