Skip to content

Commit 1f3a041

Browse files
committed
Improve Multispan
1 parent f1e23e4 commit 1f3a041

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

DataFormats/Common/interface/MultiSpan.h

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <algorithm>
66
#include <cassert>
77
#include <span>
8+
#include <stdexcept>
89
#include <vector>
910

1011
namespace edm {
@@ -19,6 +20,8 @@ namespace edm {
1920
* It is intended for iteration over heterogeneous but logically connected data ranges without copying
2021
* or merging them into a single container.
2122
*
23+
* To find a span that corresponds to a global index, a binary search is used, making the access time logarithmic in the number of spans.
24+
*
2225
*/
2326
template <typename T>
2427
class MultiSpan {
@@ -32,23 +35,34 @@ namespace edm {
3235
}
3336

3437
const T& operator[](const std::size_t globalIndex) const {
35-
assert(globalIndex < totalSize_ && "Global index out of range");
36-
38+
#ifndef NDEBUG
39+
if (globalIndex >= totalSize_) {
40+
throw std::out_of_range("Global index out of range");
41+
}
42+
#endif
3743
const auto [spanIndex, indexWithinSpan] = spanAndLocalIndex(globalIndex);
3844
return spans_[spanIndex][indexWithinSpan];
3945
}
4046

4147
std::size_t globalIndex(const std::size_t spanIndex, const std::size_t indexWithinSpan) const {
42-
assert(spanIndex < spans_.size() && "spanIndex index out of range");
43-
assert(indexWithinSpan < spans_[spanIndex].size() && "indexWithinSpan out of range");
48+
#ifndef NDEBUG
49+
if (spanIndex >= spans_.size()) {
50+
throw std::out_of_range("spanIndex index out of range");
51+
}
52+
if (indexWithinSpan >= spans_[spanIndex].size()) {
53+
throw std::out_of_range("indexWithinSpan index out of range");
54+
}
55+
#endif
4456

4557
return offsets_[spanIndex] + indexWithinSpan;
4658
}
4759

48-
inline __attribute__((always_inline)) std::pair<std::size_t, std::size_t> spanAndLocalIndex(
49-
const std::size_t globalIndex) const {
50-
assert(globalIndex < totalSize_ && "Global index out of range");
51-
60+
std::pair<std::size_t, std::size_t> spanAndLocalIndex(const std::size_t globalIndex) const {
61+
#ifndef NDEBUG
62+
if (globalIndex >= totalSize_) {
63+
throw std::out_of_range("Global index out of range");
64+
}
65+
#endif
5266
auto it = std::upper_bound(offsets_.begin(), offsets_.end(), globalIndex);
5367
std::size_t spanIndex = std::distance(offsets_.begin(), it) - 1;
5468
std::size_t indexWithinSpan = globalIndex - offsets_[spanIndex];
@@ -115,10 +129,7 @@ namespace edm {
115129

116130
bool operator==(const ConstRandomAccessIterator& other) const { return currentIndex_ == other.currentIndex_; }
117131
bool operator!=(const ConstRandomAccessIterator& other) const { return currentIndex_ != other.currentIndex_; }
118-
bool operator<(const ConstRandomAccessIterator& other) const { return currentIndex_ < other.currentIndex_; }
119-
bool operator>(const ConstRandomAccessIterator& other) const { return currentIndex_ > other.currentIndex_; }
120-
bool operator<=(const ConstRandomAccessIterator& other) const { return currentIndex_ <= other.currentIndex_; }
121-
bool operator>=(const ConstRandomAccessIterator& other) const { return currentIndex_ >= other.currentIndex_; }
132+
auto operator<=>(const ConstRandomAccessIterator& other) const { return currentIndex_ <=> other.currentIndex_; }
122133

123134
private:
124135
const MultiSpan* ms_;

DataFormats/Common/test/test_catch2_MultiSpan.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
/*
2-
* CMSSW
3-
*/
4-
#define CATCH_CONFIG_MAIN
5-
#include <catch.hpp>
6-
7-
#include "DataFormats/Common/interface/MultiSpan.h"
8-
91
#include <algorithm>
102
#include <cassert>
113
#include <cmath>
124
#include <numeric>
13-
#include <iostream>
145
#include <vector>
6+
#include <catch.hpp>
157

16-
using namespace edm;
8+
#include "DataFormats/Common/interface/MultiSpan.h"
179

1810
TEST_CASE("MultiSpan basic indexing", "[MultiSpan]") {
11+
edm::MultiSpan<int> emptyMultiSpan;
1912
edm::MultiSpan<int> ms;
2013

2114
std::vector<int> a = {1, 2, 3};
@@ -29,8 +22,22 @@ TEST_CASE("MultiSpan basic indexing", "[MultiSpan]") {
2922
static_assert(!std::is_assignable<ElementType, int>::value,
3023
"It should not be possible to assign to an element of MultiSpan; See PR #48826");
3124

25+
SECTION("Empty MultiSpan") {
26+
REQUIRE(emptyMultiSpan.size() == 0);
27+
REQUIRE(emptyMultiSpan.begin() == emptyMultiSpan.end());
28+
REQUIRE_THROWS_AS(emptyMultiSpan[0], std::out_of_range);
29+
REQUIRE_THROWS_AS(emptyMultiSpan.globalIndex(0, 0), std::out_of_range);
30+
}
31+
3232
SECTION("Size is correct") { REQUIRE(ms.size() == 5); }
3333

34+
SECTION("Range check") {
35+
REQUIRE_THROWS_AS(ms[5], std::out_of_range);
36+
REQUIRE_THROWS_AS(ms.globalIndex(2, 0), std::out_of_range);
37+
REQUIRE_THROWS_AS(ms.globalIndex(1, 2), std::out_of_range);
38+
REQUIRE_THROWS_AS(ms.spanAndLocalIndex(5), std::out_of_range);
39+
}
40+
3441
SECTION("Indexing returns correct values") {
3542
REQUIRE(ms[0] == 1);
3643
REQUIRE(ms[1] == 2);

0 commit comments

Comments
 (0)