Skip to content

Commit 60e5422

Browse files
committed
Always return (unique) pointers from parsing functions.
This avoids having to constantly switch between local variables with automatic storage duration and those on the heap that are referenced by pointers. In particular, we can get rid of the weird pointerize() function.
1 parent 7623751 commit 60e5422

15 files changed

Lines changed: 144 additions & 154 deletions

include/rds2cpp/parse_altrep.hpp

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,28 @@
2121
namespace rds2cpp {
2222

2323
template<class Source_>
24-
IntegerVector parse_integer_body(Source_&);
24+
std::unique_ptr<IntegerVector> parse_integer_body(Source_&);
2525

2626
template<class Source_>
27-
DoubleVector parse_double_body(Source_& src);
27+
std::unique_ptr<DoubleVector> parse_double_body(Source_& src);
2828

2929
template<class Source_>
3030
std::unique_ptr<RObject> parse_object(Source_&, SharedParseInfo&);
3131

3232
template<class Source_>
33-
PairList parse_pairlist_body(Source_&, const Header&, SharedParseInfo&);
33+
std::unique_ptr<PairList> parse_pairlist_body(Source_&, const Header&, SharedParseInfo&);
3434

3535
namespace altrep_internal {
3636

3737
template<class Vector_, class Source_>
38-
Vector_ parse_numeric_compact_seq(Source_& src) try {
38+
std::unique_ptr<Vector_> parse_numeric_compact_seq(Source_& src) try {
3939
auto header = parse_header(src);
4040
if (header[3] != static_cast<unsigned char>(SEXPType::REAL)) {
4141
throw std::runtime_error("expected compact_seq to store sequence information in doubles");
4242
}
4343

4444
auto info = parse_double_body(src);
45-
const auto& ranges = info.data;
45+
const auto& ranges = info->data;
4646
if (ranges.size() != 3) {
4747
throw std::runtime_error("expected compact_seq's sequence information to be of length 3");
4848
}
@@ -69,9 +69,9 @@ Vector_ parse_numeric_compact_seq(Source_& src) try {
6969
}
7070
}
7171

72-
Vector_ output(len);
72+
auto output = std::make_unique<Vector_>(len);
7373
for (I<decltype(len)> i = 0; i < len; ++i, start += step) {
74-
output.data[i] = start;
74+
output->data[i] = start;
7575
}
7676

7777
auto terminator = parse_header(src);
@@ -82,20 +82,19 @@ Vector_ parse_numeric_compact_seq(Source_& src) try {
8282
return output;
8383
} catch (std::exception& e) {
8484
throw traceback("failed to parse compact numeric ALTREP", e);
85-
return Vector_();
85+
return std::unique_ptr<Vector_>();
8686
}
8787

88-
template<class Vector, class Source_>
89-
Vector parse_attribute_wrapper(Source_& src, SharedParseInfo& shared) try {
88+
template<class Vector_, class Source_>
89+
std::unique_ptr<Vector_> parse_attribute_wrapper(Source_& src, SharedParseInfo& shared) try {
9090
auto plist_header = parse_header(src);
9191
if (plist_header[3] != static_cast<unsigned char>(SEXPType::LIST)) {
9292
throw std::runtime_error("expected pairlist in wrap_* ALTREP's payload");
9393
}
9494

9595
// First pairlist element is a CONS cell where the first value is the wrapped integer vector.
96-
9796
auto contents = parse_object(src, shared);
98-
if (contents->type() != Vector::vector_sexp_type) {
97+
if (contents->type() != Vector_::vector_sexp_type) {
9998
throw std::runtime_error("incorrectly typed contents in wrap_* ALTREP's payload");
10099
}
101100

@@ -106,45 +105,45 @@ Vector parse_attribute_wrapper(Source_& src, SharedParseInfo& shared) try {
106105
}
107106

108107
auto metadata = parse_integer_body(src);
109-
if (metadata.data.size() != 2) {
108+
if (metadata->data.size() != 2) {
110109
throw std::runtime_error("wrap_* ALTREP's metadata should be a length-2 integer vector");
111110
}
112111

113112
// Now we can finally get the attributes, which makes up the rest of the pairlist.
114-
auto coerced = static_cast<Vector*>(contents.get());
113+
std::unique_ptr<Vector_> output(static_cast<Vector_*>(contents.release()));
115114
auto attrheader = parse_header(src);
116115
if (attrheader[3] == static_cast<unsigned>(SEXPType::LIST)) {
117-
parse_attributes_body(src, attrheader, coerced->attributes, shared);
116+
parse_attributes_body(src, attrheader, output->attributes, shared);
118117
} else if (attrheader[3] != static_cast<unsigned>(SEXPType::NILVALUE_)) {
119118
throw std::runtime_error("wrap_* ALTREP's attributes should be a pairlist or NULL");
120119
}
121120

122-
return Vector(std::move(*coerced));
121+
return output;
123122
} catch (std::exception& e) {
124123
throw traceback("failed to parse attribute-wrapped ALTREP", e);
125-
return Vector();
124+
return std::unique_ptr<Vector_>();
126125
}
127126

128127
template<class Source_>
129-
StringVector parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
128+
std::unique_ptr<StringVector> parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
130129
auto plist_header = parse_header(src);
131130
if (plist_header[3] != static_cast<unsigned char>(SEXPType::LIST)) {
132131
throw std::runtime_error("expected pairlist in deferred_string ALTREP's payload");
133132
}
134133

135134
// First pairlist element is a CONS cell where the first value is the thing to be converted.
136135
auto contents = parse_object(src, shared);
137-
StringVector output;
136+
std::unique_ptr<StringVector> output;
138137

139138
if (contents->type() == SEXPType::INT){
140139
auto cast = static_cast<IntegerVector*>(contents.get());
141140
const auto n = cast->data.size();
142-
output = StringVector(n);
141+
output = std::make_unique<StringVector>(n);
143142

144143
for (I<decltype(n)> i = 0; i < n; ++i) {
145144
if (cast->data[i] != std::numeric_limits<std::int32_t>::min()) { // see altrep.c.
146-
output.data[i].value = std::to_string(cast->data[i]);
147-
output.data[i].encoding = StringEncoding::ASCII;
145+
output->data[i].value = std::to_string(cast->data[i]);
146+
output->data[i].encoding = StringEncoding::ASCII;
148147
}
149148
}
150149

@@ -153,15 +152,15 @@ StringVector parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
153152
converter.precision(std::numeric_limits<double>::max_digits10);
154153
auto cast = static_cast<DoubleVector*>(contents.get());
155154
const bool lw = (little_endian() ? 0 : 1); // see arithmetic.c.
156-
output = StringVector(cast->data.size());
155+
output = std::make_unique<StringVector>(cast->data.size());
157156

158157
const auto datalen = cast->data.size();
159158
for (I<decltype(datalen)> i = 0; i < datalen; ++i) {
160-
output.data[i].encoding = StringEncoding::ASCII;
159+
output->data[i].encoding = StringEncoding::ASCII;
161160

162161
if (std::isfinite(cast->data[i])) {
163162
converter << cast->data[i];
164-
output.data[i].value = converter.str();
163+
output->data[i].value = converter.str();
165164
converter.str(std::string());
166165

167166
} else if (std::isnan(cast->data[i])) {
@@ -177,14 +176,14 @@ StringVector parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
177176
if (payload == 1954) {
178177
// Missing values are represented by the default unset value of String::value.
179178
} else {
180-
output.data[i].value = "NaN";
179+
output->data[i].value = "NaN";
181180
}
182181

183182
} else if (std::isinf(cast->data[i])) {
184183
if (cast->data[i] > 0) {
185-
output.data[i].value = "Inf";
184+
output->data[i].value = "Inf";
186185
} else {
187-
output.data[i].value = "-Inf";
186+
output->data[i].value = "-Inf";
188187
}
189188
}
190189
}
@@ -200,7 +199,7 @@ StringVector parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
200199
}
201200

202201
auto metadata = parse_integer_body(src);
203-
if (metadata.data.size() != 1) {
202+
if (metadata->data.size() != 1) {
204203
throw std::runtime_error("deferred_string ALTREP's metadata should be a length-1 integer vector");
205204
}
206205

@@ -213,7 +212,7 @@ StringVector parse_deferred_string(Source_& src, SharedParseInfo& shared) try {
213212
return output;
214213
} catch (std::exception& e) {
215214
throw traceback("failed to parse deferred string ALTREP", e);
216-
return StringVector();
215+
return std::make_unique<StringVector>();
217216
}
218217

219218
}
@@ -226,24 +225,20 @@ std::unique_ptr<RObject> parse_altrep_body(Source_& src, SharedParseInfo& shared
226225
}
227226

228227
auto plist = parse_pairlist_body(src, header, shared);
229-
if (plist.data.size() < 1 || plist.data[0].value->type() != SEXPType::SYM) {
228+
if (plist->data.size() < 1 || plist->data[0].value->type() != SEXPType::SYM) {
230229
throw std::runtime_error("expected type specification symbol in the ALTREP description");
231230
}
232231

233232
std::unique_ptr<RObject> output;
234-
auto pointerize_ = [&](auto x) -> void {
235-
pointerize(output, std::move(x));
236-
};
237-
238-
auto sdx = static_cast<SymbolIndex*>(plist.data[0].value.get());
233+
auto sdx = static_cast<SymbolIndex*>(plist->data[0].value.get());
239234
const auto& symb = shared.symbols[sdx->index];
240235

241236
if (symb.name == "wrap_integer") {
242-
pointerize_(altrep_internal::parse_attribute_wrapper<IntegerVector>(src, shared));
237+
output = altrep_internal::parse_attribute_wrapper<IntegerVector>(src, shared);
243238
} else if (symb.name == "compact_intseq") {
244-
pointerize_(altrep_internal::parse_numeric_compact_seq<IntegerVector>(src));
239+
output = altrep_internal::parse_numeric_compact_seq<IntegerVector>(src);
245240
} else if (symb.name == "deferred_string") {
246-
pointerize_(altrep_internal::parse_deferred_string(src, shared));
241+
output = altrep_internal::parse_deferred_string(src, shared);
247242
} else {
248243
throw std::runtime_error("unrecognized ALTREP type '" + symb.name + "'");
249244
}

include/rds2cpp/parse_atomic.hpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <vector>
66
#include <algorithm>
77
#include <stdexcept>
8+
#include <memory>
89

910
#include "RObject.hpp"
1011
#include "utils_parse.hpp"
@@ -16,15 +17,15 @@ namespace rds2cpp {
1617

1718
namespace atomic_internal {
1819

19-
template<class Vector, class Source_>
20-
Vector parse_integer_or_logical_body(Source_& src) {
20+
template<class Vector_, class Source_>
21+
std::unique_ptr<Vector_> parse_integer_or_logical_body(Source_& src) {
2122
const auto len = get_length(src);
22-
Vector output(len);
23+
auto output = std::make_unique<Vector_>(len);
2324

2425
constexpr int width = 4;
25-
static_assert(width == sizeof(decltype(output.data[0])));
26+
static_assert(width == sizeof(decltype(output->data[0])));
2627
const auto byte_length = sanisizer::product_unsafe<std::size_t>(width, len); // must be safe if we successfully allocated output.data.
27-
auto ptr = reinterpret_cast<unsigned char*>(output.data.data());
28+
auto ptr = reinterpret_cast<unsigned char*>(output->data.data());
2829
quick_extract(src, byte_length, ptr);
2930

3031
// Flipping endianness.
@@ -41,30 +42,30 @@ Vector parse_integer_or_logical_body(Source_& src) {
4142
}
4243

4344
template<class Source_>
44-
IntegerVector parse_integer_body(Source_& src) try {
45+
std::unique_ptr<IntegerVector> parse_integer_body(Source_& src) try {
4546
return atomic_internal::parse_integer_or_logical_body<IntegerVector>(src);
4647
} catch (std::exception& e) {
4748
throw traceback("failed to parse data for an integer vector", e);
48-
return IntegerVector();
49+
return std::unique_ptr<IntegerVector>();
4950
}
5051

5152
template<class Source_>
52-
LogicalVector parse_logical_body(Source_& src) try {
53+
std::unique_ptr<LogicalVector> parse_logical_body(Source_& src) try {
5354
return atomic_internal::parse_integer_or_logical_body<LogicalVector>(src);
5455
} catch (std::exception& e) {
5556
throw traceback("failed to parse data for a logical vector", e);
56-
return LogicalVector();
57+
return std::unique_ptr<LogicalVector>();
5758
}
5859

5960
template<class Source_>
60-
DoubleVector parse_double_body(Source_& src) try {
61+
std::unique_ptr<DoubleVector> parse_double_body(Source_& src) try {
6162
const auto len = get_length(src);
62-
DoubleVector output(len);
63+
auto output = std::make_unique<DoubleVector>(len);
6364

6465
constexpr int width = 8;
65-
static_assert(width == sizeof(decltype(output.data[0])));
66-
const auto byte_length = sanisizer::product_unsafe<std::size_t>(width, len); // must be safe if we successfully allocated output.data.
67-
auto ptr = reinterpret_cast<unsigned char*>(output.data.data());
66+
static_assert(width == sizeof(decltype(output->data[0])));
67+
const auto byte_length = sanisizer::product_unsafe<std::size_t>(width, len); // must be safe if we successfully allocated output->data.
68+
auto ptr = reinterpret_cast<unsigned char*>(output->data.data());
6869
quick_extract(src, byte_length, ptr);
6970

7071
// Flipping endianness.
@@ -78,32 +79,32 @@ DoubleVector parse_double_body(Source_& src) try {
7879
return output;
7980
} catch (std::exception& e) {
8081
throw traceback("failed to parse data for a double vector", e);
81-
return DoubleVector();
82+
return std::unique_ptr<DoubleVector>();
8283
}
8384

8485
template<class Source_>
85-
RawVector parse_raw_body(Source_& src) try {
86+
std::unique_ptr<RawVector> parse_raw_body(Source_& src) try {
8687
const auto len = get_length(src);
87-
RawVector output(len);
88+
auto output = std::make_unique<RawVector>(len);
8889

89-
auto ptr = reinterpret_cast<unsigned char*>(output.data.data());
90+
auto ptr = reinterpret_cast<unsigned char*>(output->data.data());
9091
quick_extract(src, len, ptr);
9192

9293
return output;
9394
} catch (std::exception& e) {
9495
throw traceback("failed to parse data for a raw vector", e);
95-
return RawVector();
96+
return std::unique_ptr<RawVector>();
9697
}
9798

9899
template<class Source_>
99-
ComplexVector parse_complex_body(Source_& src) try {
100+
std::unique_ptr<ComplexVector> parse_complex_body(Source_& src) try {
100101
const auto len = get_length(src);
101-
ComplexVector output(len);
102+
auto output = std::make_unique<ComplexVector>(len);
102103

103104
constexpr int width = 16;
104-
static_assert(width == sizeof(decltype(output.data[0])));
105-
const auto byte_length = sanisizer::product_unsafe<std::size_t>(width, len); // must be safe if we successfully allocated output.data.
106-
auto ptr = reinterpret_cast<unsigned char*>(output.data.data());
105+
static_assert(width == sizeof(decltype(output->data[0])));
106+
const auto byte_length = sanisizer::product_unsafe<std::size_t>(width, len); // must be safe if we successfully allocated output->data.
107+
auto ptr = reinterpret_cast<unsigned char*>(output->data.data());
107108
quick_extract(src, byte_length, ptr);
108109

109110
// Flipping endianness for each double.
@@ -119,20 +120,20 @@ ComplexVector parse_complex_body(Source_& src) try {
119120
return output;
120121
} catch (std::exception& e) {
121122
throw traceback("failed to parse data for a complex vector", e);
122-
return ComplexVector();
123+
return std::unique_ptr<ComplexVector>();
123124
}
124125

125126
template<class Source_>
126-
StringVector parse_string_body(Source_& src) try {
127+
std::unique_ptr<StringVector> parse_string_body(Source_& src) try {
127128
const auto len = get_length(src);
128-
StringVector output(len);
129+
auto output = std::make_unique<StringVector>(len);
129130
for (I<decltype(len)> i = 0; i < len; ++i) {
130-
output.data[i] = parse_single_string(src);
131+
output->data[i] = parse_single_string(src);
131132
}
132133
return output;
133134
} catch (std::exception& e) {
134135
throw traceback("failed to parse data for a string vector", e);
135-
return StringVector();
136+
return std::unique_ptr<StringVector>();
136137
}
137138

138139
}

include/rds2cpp/parse_attributes.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace rds2cpp {
1212

1313
template<class Source_>
14-
PairList parse_pairlist_body(Source_&, const Header&, SharedParseInfo&);
14+
std::unique_ptr<PairList> parse_pairlist_body(Source_&, const Header&, SharedParseInfo&);
1515

1616
inline bool has_attributes(const Header& header) {
1717
return (header[2] & 0x2);
@@ -20,9 +20,9 @@ inline bool has_attributes(const Header& header) {
2020
template<class Source_>
2121
void parse_attributes_body(Source_& src, const Header& header, std::vector<Attribute>& output, SharedParseInfo& shared) try {
2222
auto plist = parse_pairlist_body(src, header, shared);
23-
output.reserve(plist.data.size());
23+
output.reserve(plist->data.size());
2424

25-
for (auto& entry : plist.data) {
25+
for (auto& entry : plist->data) {
2626
if (!(entry.tag.has_value())) {
2727
throw std::runtime_error("all attributes should be named");
2828
}

include/rds2cpp/parse_builtin.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@
1010
namespace rds2cpp {
1111

1212
template<class Source_>
13-
BuiltInFunction parse_builtin_body(Source_& src) try {
13+
std::unique_ptr<BuiltInFunction> parse_builtin_body(Source_& src) try {
1414
const auto len = get_length(src);
1515

16-
BuiltInFunction output;
17-
output.name.reserve(len); // don't resize and use extract() on string::data, as that pointer is read-only AFAICT.
16+
auto output = std::make_unique<BuiltInFunction>();
17+
output->name.reserve(len); // don't resize and use extract() on string::data, as that pointer is read-only AFAICT.
1818
for (I<decltype(len)> i = 0; i < len; ++i) {
1919
if (!src.advance()) {
2020
throw empty_error();
2121
}
22-
output.name.push_back(as_char(src.get()));
22+
output->name.push_back(as_char(src.get()));
2323
}
2424

2525
return output;
2626
} catch(std::exception& e) {
2727
throw traceback("failed to parse built-in function body", e);
28-
return BuiltInFunction();
28+
return std::unique_ptr<BuiltInFunction>();
2929
}
3030

3131
}

0 commit comments

Comments
 (0)