Skip to content

Commit e635a7a

Browse files
authored
Merge pull request #47770 from Dr15Jones/fix_ESGetToken
Manage memory for ESGetToken's productLabel
2 parents 0caba03 + 9530f04 commit e635a7a

File tree

4 files changed

+197
-2
lines changed

4 files changed

+197
-2
lines changed

FWCore/Utilities/interface/ESGetToken.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "FWCore/Utilities/interface/ESInputTag.h"
1818
#include "FWCore/Utilities/interface/ESIndices.h"
19+
#include "FWCore/Utilities/interface/OftenEmptyCString.h"
1920
#include <limits>
2021

2122
namespace edm {
@@ -69,8 +70,8 @@ namespace edm {
6970
explicit constexpr ESGetToken(unsigned int transitionID, ESTokenIndex index, char const* productLabel) noexcept
7071
: m_productLabel{productLabel}, m_transitionID{transitionID}, m_index{index} {}
7172

72-
constexpr char const* productLabel() const noexcept { return m_productLabel; }
73-
char const* m_productLabel{nullptr};
73+
constexpr char const* productLabel() const noexcept { return m_productLabel.c_str(); }
74+
OftenEmptyCString m_productLabel{nullptr};
7475
// Note that for ESProducers, m_transitionID is actually a produceMethodID
7576
// (count of the setWhatProduced methods in the ESProducer)
7677
unsigned int m_transitionID{std::numeric_limits<unsigned int>::max()};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef FWCore_Utilities_OftenEmptyCString_h
2+
#define FWCore_Utilities_OftenEmptyCString_h
3+
4+
/* Class is optimized to not require any additional memory
5+
if the string passes is empty. A nullptr will be replaced with
6+
the empty string as well.
7+
*/
8+
9+
namespace edm {
10+
class OftenEmptyCString {
11+
public:
12+
OftenEmptyCString() : m_value(emptyString()) {}
13+
~OftenEmptyCString();
14+
explicit OftenEmptyCString(const char*);
15+
OftenEmptyCString(OftenEmptyCString const&);
16+
OftenEmptyCString(OftenEmptyCString&&) noexcept;
17+
OftenEmptyCString& operator=(OftenEmptyCString const&);
18+
OftenEmptyCString& operator=(OftenEmptyCString&&) noexcept;
19+
20+
const char* c_str() const noexcept { return m_value; }
21+
22+
private:
23+
static const char* emptyString();
24+
void deleteIfNotEmpty();
25+
char const* m_value;
26+
};
27+
} // namespace edm
28+
29+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "FWCore/Utilities/interface/OftenEmptyCString.h"
2+
#include <cstring>
3+
#include <utility>
4+
5+
namespace edm {
6+
OftenEmptyCString::OftenEmptyCString(const char* iValue) {
7+
if (iValue == nullptr or iValue[0] == '\0') {
8+
m_value = emptyString();
9+
} else {
10+
auto l = strlen(iValue);
11+
auto temp = new char[l + 1];
12+
strncpy(temp, iValue, l + 1);
13+
m_value = temp;
14+
}
15+
}
16+
void OftenEmptyCString::deleteIfNotEmpty() {
17+
if (m_value != emptyString()) {
18+
delete[] m_value;
19+
}
20+
}
21+
OftenEmptyCString::~OftenEmptyCString() { deleteIfNotEmpty(); }
22+
23+
OftenEmptyCString::OftenEmptyCString(OftenEmptyCString const& iOther) : OftenEmptyCString(iOther.m_value) {}
24+
OftenEmptyCString::OftenEmptyCString(OftenEmptyCString&& iOther) noexcept : m_value(iOther.m_value) {
25+
iOther.m_value = nullptr;
26+
}
27+
OftenEmptyCString& OftenEmptyCString::operator=(OftenEmptyCString const& iOther) {
28+
if (iOther.m_value != m_value) {
29+
OftenEmptyCString temp{iOther};
30+
*this = std::move(temp);
31+
}
32+
return *this;
33+
}
34+
OftenEmptyCString& OftenEmptyCString::operator=(OftenEmptyCString&& iOther) noexcept {
35+
if (iOther.m_value != m_value) {
36+
deleteIfNotEmpty();
37+
m_value = iOther.m_value;
38+
iOther.m_value = nullptr;
39+
}
40+
return *this;
41+
}
42+
43+
const char* OftenEmptyCString::emptyString() {
44+
constexpr static const char* s_empty = "";
45+
return s_empty;
46+
}
47+
48+
} // namespace edm
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include "catch.hpp"
2+
#include "FWCore/Utilities/interface/OftenEmptyCString.h"
3+
#include <cstring>
4+
5+
TEST_CASE("test edm::OftenEmptyCString", "[OftenEmptyCString]") {
6+
SECTION("Constructors") {
7+
SECTION("default") {
8+
edm::OftenEmptyCString s;
9+
REQUIRE(s.c_str() != nullptr);
10+
REQUIRE(s.c_str()[0] == '\0');
11+
}
12+
SECTION("from const *") {
13+
SECTION("nullptr") {
14+
edm::OftenEmptyCString s(nullptr);
15+
REQUIRE(s.c_str() != nullptr);
16+
REQUIRE(s.c_str()[0] == '\0');
17+
}
18+
SECTION("empty") {
19+
const char* kEmpty = "";
20+
edm::OftenEmptyCString s(kEmpty);
21+
REQUIRE(s.c_str() != nullptr);
22+
REQUIRE(s.c_str() != kEmpty);
23+
REQUIRE(s.c_str()[0] == '\0');
24+
}
25+
SECTION("non empty string") {
26+
const char* kValue = "something";
27+
edm::OftenEmptyCString s(kValue);
28+
REQUIRE(s.c_str() != nullptr);
29+
REQUIRE(s.c_str() != kValue);
30+
REQUIRE(strncmp(kValue, s.c_str(), 9) == 0);
31+
REQUIRE(strlen(kValue) == strlen(s.c_str()));
32+
}
33+
}
34+
SECTION("Copy") {
35+
SECTION("from non empty") {
36+
edm::OftenEmptyCString s("something");
37+
edm::OftenEmptyCString copy(s);
38+
REQUIRE(s.c_str() != copy.c_str());
39+
REQUIRE(strcmp(s.c_str(), copy.c_str()) == 0);
40+
}
41+
SECTION("from default") {
42+
edm::OftenEmptyCString s;
43+
edm::OftenEmptyCString copy(s);
44+
REQUIRE(s.c_str() == copy.c_str());
45+
REQUIRE(s.c_str() != nullptr);
46+
REQUIRE(strlen(s.c_str()) == 0);
47+
}
48+
}
49+
SECTION("Move") {
50+
SECTION("from non empty") {
51+
edm::OftenEmptyCString s("something");
52+
edm::OftenEmptyCString copy(std::move(s));
53+
REQUIRE(s.c_str() != copy.c_str());
54+
REQUIRE(s.c_str() == nullptr);
55+
REQUIRE(strcmp("something", copy.c_str()) == 0);
56+
}
57+
SECTION("from default") {
58+
edm::OftenEmptyCString s;
59+
edm::OftenEmptyCString copy(std::move(s));
60+
REQUIRE(s.c_str() == nullptr);
61+
REQUIRE(copy.c_str() == edm::OftenEmptyCString().c_str());
62+
}
63+
}
64+
}
65+
SECTION("operator=") {
66+
SECTION("copy version") {
67+
SECTION("from non empty to non empty") {
68+
edm::OftenEmptyCString s("something");
69+
edm::OftenEmptyCString copy("else");
70+
copy = s;
71+
REQUIRE(s.c_str() != copy.c_str());
72+
REQUIRE(strcmp("something", copy.c_str()) == 0);
73+
REQUIRE(strcmp(s.c_str(), copy.c_str()) == 0);
74+
}
75+
SECTION("from default to non empty") {
76+
edm::OftenEmptyCString s;
77+
edm::OftenEmptyCString copy("original");
78+
copy = s;
79+
REQUIRE(strcmp(s.c_str(), copy.c_str()) == 0);
80+
}
81+
SECTION("from non empty to empty") {
82+
edm::OftenEmptyCString s("something");
83+
edm::OftenEmptyCString copy;
84+
copy = s;
85+
REQUIRE(s.c_str() != copy.c_str());
86+
REQUIRE(strcmp("something", copy.c_str()) == 0);
87+
REQUIRE(strcmp(s.c_str(), copy.c_str()) == 0);
88+
}
89+
}
90+
SECTION("move version") {
91+
SECTION("from non empty to non empty") {
92+
edm::OftenEmptyCString s("something");
93+
edm::OftenEmptyCString copy("else");
94+
copy = std::move(s);
95+
REQUIRE(s.c_str() != copy.c_str());
96+
REQUIRE(s.c_str() == nullptr);
97+
REQUIRE(strcmp("something", copy.c_str()) == 0);
98+
}
99+
SECTION("from default to non empty") {
100+
edm::OftenEmptyCString s;
101+
edm::OftenEmptyCString copy("original");
102+
copy = std::move(s);
103+
REQUIRE(copy.c_str() != nullptr);
104+
REQUIRE(copy.c_str()[0] == '\0');
105+
REQUIRE(s.c_str() == nullptr);
106+
}
107+
SECTION("from non empty to empty") {
108+
edm::OftenEmptyCString s("something");
109+
edm::OftenEmptyCString copy;
110+
copy = std::move(s);
111+
REQUIRE(s.c_str() != copy.c_str());
112+
REQUIRE(s.c_str() == nullptr);
113+
REQUIRE(strcmp("something", copy.c_str()) == 0);
114+
}
115+
}
116+
}
117+
}

0 commit comments

Comments
 (0)