GCC Code Coverage Report


Directory: ./
File: TestVirtualDataPtr.cpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 38 38 100.0%
Functions: 17 17 100.0%
Branches: 48 180 26.7%

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 "compat/gsl14.hpp"
7 #include "compat/memory14.hpp"
8
9 class StackPtr {
10 public:
11 // The base class has a normal constructor that provides its own object.
12 explicit StackPtr(gsl::index size = 1);
13
14 public:
15 void Push(double x);
16 double Pop();
17
18 protected:
19 // The base class has a constructor that accepts an object from a derived class.
20 StackPtr(std::unique_ptr<Array> data);
21
22 private:
23 // To simulate virtual data in C++, the base class has a pointer to the
24 // member object and the base class’s destructor deletes the object.
25 // Some additional memory allocation overhead is imposed.
26 std::unique_ptr<Array> data_;
27 gsl::index index_{0};
28 };
29
30 ////////////////////////////////////////////////////////////////////////////////
31
32 // Virtual data makes the implementation of the derived class easier:
33 // most of the implementation is inherited.
34 class StretchableStackPtr : public StackPtr {
35 public:
36 // The derived class has a constructor that provides a new object to the base class.
37 explicit StretchableStackPtr(gsl::index size = 1);
38 };
39
40 ////////////////////////////////////////////////////////////////////////////////
41
42
1/2
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
3 StackPtr::StackPtr(gsl::index size) : StackPtr(std::make_unique<Array>(size)) {}
43
44 8 StackPtr::StackPtr(std::unique_ptr<Array> data) : data_{std::move(data)} {}
45
46 11 void StackPtr::Push(double x) {
47 11 (*data_)[index_++] = x; // may throw
48 10 }
49
50 8 double StackPtr::Pop() {
51 8 return (*data_)[--index_]; // may throw
52 }
53
54 ////////////////////////////////////////////////////////////////////////////////
55
56 1 StretchableStackPtr::StretchableStackPtr(gsl::index size) :
57
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 StackPtr{std::make_unique<StretchableArray>(size)} {}
58
59 ////////////////////////////////////////////////////////////////////////////////
60
61 #include <gtest/gtest.h>
62
63 8 TEST(VirtualDataPtr, Stack_Push_Pop) {
64 2 const auto size = gsl::index{3};
65
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
6 auto stack = Verbose<StackPtr>{"stack", size};
66
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = gsl::index{0}; x < size; x++) {
67
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 stack.Push(gsl::narrow_cast<double>(x));
68 }
69
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = size - 1; x >= 0; x--) {
70
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());
71 }
72 4 }
73
74 8 TEST(VirtualDataPtr, Stack_Push_Full) {
75 2 const auto size = gsl::index{3};
76
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
6 auto stack = Verbose<StackPtr>{"stack", size};
77
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = gsl::index{0}; x < size; x++) {
78
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 stack.Push(gsl::narrow_cast<double>(x));
79 }
80
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);
81 4 }
82
83 8 TEST(VirtualDataPtr, Stack_Pop_Empty) {
84
2/4
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
6 auto stack = Verbose<StackPtr>{"stack", 1};
85
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);
86 4 }
87
88 8 TEST(VirtualDataPtr, Stack_Stretch) {
89 2 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<StretchableStackPtr>{"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
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)));
95
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());
96
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
8 for (auto x = size - 1; x >= 0; x--) {
97
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());
98 }
99 4 }
100