88#include < sstream>
99#include < limits>
1010#include < memory>
11+ #include < array>
12+ #include < type_traits>
1113
1214#include " RObject.hpp"
1315#include " utils_parse.hpp"
@@ -32,8 +34,8 @@ PairList parse_pairlist_body(Source_&, const Header&, SharedParseInfo&);
3234
3335namespace altrep_internal {
3436
35- template <class Vector , class Source_ >
36- Vector parse_numeric_compact_seq (Source_& src) try {
37+ template <class Vector_ , class Source_ >
38+ Vector_ parse_numeric_compact_seq (Source_& src) try {
3739 auto header = parse_header (src);
3840 if (header[3 ] != static_cast <unsigned char >(SEXPType::REAL)) {
3941 throw std::runtime_error (" expected compact_seq to store sequence information in doubles" );
@@ -45,10 +47,29 @@ Vector parse_numeric_compact_seq(Source_& src) try {
4547 throw std::runtime_error (" expected compact_seq's sequence information to be of length 3" );
4648 }
4749
48- auto len = sanisizer::from_float<std::size_t >(ranges[0 ]);
50+ const auto len = sanisizer::from_float<std::size_t >(ranges[0 ]);
4951 double start = ranges[1 ], step = ranges[2 ];
5052
51- Vector output (len);
53+ typedef I<decltype (std::declval<Vector_>().data [0 ])> VectorValue;
54+ if constexpr (std::is_integral<VectorValue>::value) {
55+ static_assert (std::is_signed<VectorValue>::value);
56+ if (len) {
57+ std::array<double , 2 > endpts { start, start + (ranges[0 ] - 1 ) * step };
58+ constexpr int available_bits = std::numeric_limits<VectorValue>::digits;
59+ for (auto x : endpts) {
60+ if (!std::isfinite (x)) {
61+ throw std::runtime_error (" non-finite boundaries for integer compact_seq" );
62+ }
63+ const auto target = (x >= 0 ? x : 1 - x); // +1 as negative values get a bit more space in signed integers.
64+ int bits = sanisizer::required_bits_for_float (std::trunc (target));
65+ if (bits > available_bits) {
66+ throw std::runtime_error (" overflow for integer compact_seq" );
67+ }
68+ }
69+ }
70+ }
71+
72+ Vector_ output (len);
5273 for (I<decltype (len)> i = 0 ; i < len; ++i, start += step) {
5374 output.data [i] = start;
5475 }
@@ -61,7 +82,7 @@ Vector parse_numeric_compact_seq(Source_& src) try {
6182 return output;
6283} catch (std::exception& e) {
6384 throw traceback (" failed to parse compact numeric ALTREP" , e);
64- return Vector ();
85+ return Vector_ ();
6586}
6687
6788template <class Vector , class Source_ >
0 commit comments