GCC Code Coverage Report


Directory: ./
File: Array.cpp
Date: 2026-03-21 20:51:59
Exec Total Coverage
Lines: 46 46 100.0%
Functions: 12 12 100.0%
Branches: 16 28 57.1%

Line Branch Exec Source
1 #include "Array.hpp"
2 #include "compat/memory14.hpp"
3
4 // constructor
5 14 Array::Array(gsl::index size) :
6 14 size_{size},
7 28 data_{std::make_unique<double[]>(size_)} { // NOLINT(*-avoid-c-arrays)
8 14 }
9
10 // copy constructor (deep copy)
11 // explicitly invoke Verbose copy constructor
12 // instead of delegating to another constructor
13 1 Array::Array(const Array& other) :
14 1 size_{other.size_},
15 2 data_{std::make_unique<double[]>(size_)} { // NOLINT(*-avoid-c-arrays)}
16 1 const auto* begin = other.data_.get();
17 2 const auto* end =
18 1 begin + other.size_; // NOLINT *-pro-bounds-pointer-arithmetic
19 1 auto* out = data_.get();
20
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::copy(begin, end, out);
21 1 }
22
23 // move constructor
24 // explicitlly invoke Verbose move constructor
25 // instead of delgating to default constructor
26 // see [What is the copy-and-swap idiom?]
27 // (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom)
28 2 Array::Array(Array&& other) noexcept {
29 2 swap(*this, other); // other becomes empty
30 2 }
31
32 // copy assignment operator
33 1 Array& Array::operator=(const Array& other) {
34
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 assign(other); // copy constructor may throw
35 1 return *this;
36 }
37
38 // move assignment operator
39 1 Array& Array::operator=(Array&& other) noexcept {
40 2 assign(std::move(other)); // move constructor is noexcept
41 1 return *this;
42 }
43
44 // unified assignment
45 // see [What is the copy-and-swap idiom?]
46 // (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom)
47 // see Item 11: [Handle assignment to self in operator=]
48 // (https://learning.oreilly.com/library/view/effective-c-third/0321334876/ch02.html#ch02lev1sec7)
49 2 void Array::assign(Array other) noexcept { // pass by value
50 using std::swap; // enable argument dependent lookup
51 2 swap(*this, other);
52 2 }
53
54 // non-member swap
55 4 void swap(Array& left, Array& right) noexcept {
56 using std::swap; // enable Argument Dependent Lookup
57 4 swap(left.size_, right.size_);
58 4 swap(left.data_, right.data_);
59 4 }
60
61 6 gsl::index Array::size() const noexcept { return size_; }
62
63 12 const double& Array::operator[](gsl::index i) const {
64 12 check_bounds(i);
65 12 return data_[i];
66 }
67
68 61 double& Array::operator[](gsl::index i) {
69 61 reserve(i);
70 61 check_bounds(i);
71 57 return data_[i];
72 }
73
74 // see ES.50: [Don't cast away const]
75 // (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-casts-const)
76 // see Item 3: Use const whenever possible:
77 // [Avoiding duplication in const and non-const member functions]
78 // (https://learning.oreilly.com/library/view/effective-c-third/0321334876/ch01.html#ch01lev2sec2)
79 73 void Array::check_bounds(gsl::index i) const {
80
2/2
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 71 times.
73 if (i >= size_) {
81 throw std::out_of_range(
82
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 "index exceeds size: " + std::to_string(i)
83
4/8
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 21 taken 2 times.
✗ Branch 22 not taken.
6 + ">=" + std::to_string(size_));
84 }
85
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 69 times.
71 else if (i < 0) {
86 throw std::out_of_range(
87
4/8
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 2 times.
✗ Branch 18 not taken.
2 "index is negative: " + std::to_string(i) + "< 0");
88 }
89 69 }
90
91 37 void Array::reserve(gsl::index) {
92 // Does nothing in base class.
93 37 }
94