GCC Code Coverage Report


Directory: ./
File: TestVirtualDataRef.cpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 45 45 100.0%
Functions: 17 17 100.0%
Branches: 54 192 28.1%

Line Branch Exec Source
1 // See [What is “virtual data,” and how-can / why-would I use it in C++?]
2 // (https://isocpp.org/wiki/faq/value-vs-ref-semantics#virt-data)
3
4 #include "StretchableArray.hpp"
5 #include "Verbose.hpp"
6 #include <functional>
7 #include <iostream>
8
9 class StackRef {
10 public:
11 void Push(double x);
12 double Pop();
13
14 protected:
15 // The base class has no public constructor and does not provide its own
16 // object. Instead it accepts an object from a derived class.
17 StackRef(Array& data);
18
19 private:
20 // To simulate virtual data in C++, the base class has a reference to the
21 // member object and the derived class’s destructor deletes the object.
22 // No additional memory allocation overhead is imposed,
23 // but copy assignment becomes impossible.
24 std::reference_wrapper<Array> data_;
25 gsl::index index_{0};
26 };
27
28 ////////////////////////////////////////////////////////////////////////////////
29
30 // Virtual data makes the implementation of the derived class easier:
31 // most of the implementation is inherited.
32 class FixedStackRef : public StackRef {
33 public:
34 // The derived class has a constructor that provides an object to the base class.
35 explicit FixedStackRef(gsl::index size = 1);
36
37 private:
38 // The derived class contains the member object.
39 Array value_;
40 };
41
42 ////////////////////////////////////////////////////////////////////////////////
43
44 // Virtual data makes the implementation of the derived class easier:
45 // most of the implementation is inherited.
46 class StretchableStackRef : public StackRef {
47 public:
48 // The derived class has a constructor that provides an object to the base class.
49 explicit StretchableStackRef(gsl::index size = 1);
50
51 private:
52 // The derived class contains the member object.
53 StretchableArray value_;
54 };
55
56 ////////////////////////////////////////////////////////////////////////////////
57
58 4 StackRef::StackRef(Array& data) : data_{data} {
59 4 std::cout << gsl::czstring{__func__} << ": &data_=" << &data_.get()
60 4 << std::endl;
61 4 }
62
63 11 void StackRef::Push(double x) {
64 11 data_.get()[index_++] = x; // may throw
65 10 }
66
67 8 double StackRef::Pop() {
68 8 return data_.get()[--index_]; // may throw
69 }
70
71 ////////////////////////////////////////////////////////////////////////////////
72
73 3 FixedStackRef::FixedStackRef(gsl::index size) : StackRef{value_}, value_{size} {
74
4/8
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
3 std::cout << gsl::czstring{__func__} << ": &value_=" << &value_ << std::endl;
75 3 }
76
77 ////////////////////////////////////////////////////////////////////////////////
78
79 1 StretchableStackRef::StretchableStackRef(gsl::index size) :
80 1 StackRef{value_}, value_{size} {
81
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
1 std::cout << gsl::czstring{__func__} << ": &value_=" << &value_ << std::endl;
82 1 }
83
84 ////////////////////////////////////////////////////////////////////////////////
85
86 #include <gtest/gtest.h>
87
88 8 TEST(VirtualDataRef, Stack_Push_Pop) {
89 2 const auto size = gsl::index{3};
90
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
6 auto stack = Verbose<FixedStackRef>{"stack", size};
91
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = gsl::index{0}; x < size; x++) {
92
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 stack.Push(gsl::narrow_cast<double>(x));
93 }
94
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = size - 1; x >= 0; x--) {
95
3/12
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
6 EXPECT_EQ(gsl::narrow_cast<double>(x), stack.Pop());
96 }
97 4 }
98
99 8 TEST(VirtualDataRef, Stack_Push_Full) {
100 2 auto size = gsl::index{3};
101
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
6 auto stack = Verbose<FixedStackRef>{"stack", size};
102
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = gsl::index{0}; x < size; x++) {
103
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 stack.Push(gsl::narrow_cast<double>(x));
104 }
105
6/37
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 41 taken 1 times.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
2 EXPECT_THROW(stack.Push(gsl::narrow_cast<double>(size)), std::out_of_range);
106 4 }
107
108 8 TEST(VirtualDataRef, Stack_Pop_Empty) {
109
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
6 auto stack = Verbose<FixedStackRef>{"stack", 1};
110
6/37
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 39 taken 1 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
2 EXPECT_THROW(stack.Pop(), std::out_of_range);
111 4 }
112
113 8 TEST(VirtualDataRef, Stack_Stretch) {
114 2 const auto size = gsl::index{3};
115
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
6 auto stack = Verbose<StretchableStackRef>{"stack", size};
116
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = gsl::index{0}; x < size; x++) {
117
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 stack.Push(gsl::narrow_cast<double>(x));
118 }
119
4/34
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
2 EXPECT_NO_THROW(stack.Push(gsl::narrow_cast<double>(size)));
120
3/12
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
2 EXPECT_EQ(gsl::narrow_cast<double>(size), stack.Pop());
121
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = size - 1; x >= 0; x--) {
122
3/12
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
6 EXPECT_EQ(gsl::narrow_cast<double>(x), stack.Pop());
123 }
124 4 }
125