Skip to content

Commit 4f7ec1b

Browse files
committed
Robustify IntVect and RealVect read
In the old approach, inputs like `(3,2` without closing `)` are silently accepted. Maintain backward compatibility. Consolidate IntVect and RealVector I/O.
1 parent 7e9ce72 commit 4f7ec1b

File tree

7 files changed

+136
-151
lines changed

7 files changed

+136
-151
lines changed

Src/Base/AMReX_Box.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ box_write (std::ostream& os,
2525
int dim)
2626
{
2727
os << '(';
28-
int_vector_write(os, smallend, dim) << ' ';
29-
int_vector_write(os, bigend, dim) << ' ';
30-
int_vector_write(os, type, dim) << ')';
28+
T_vector_write(os, smallend, dim) << ' ';
29+
T_vector_write(os, bigend, dim) << ' ';
30+
T_vector_write(os, type, dim) << ')';
3131

3232
if (os.fail()) {
3333
amrex::Error("operator<<(ostream&,Box&) failed");
@@ -58,28 +58,28 @@ box_read (std::istream& is,
5858

5959
if (c == '(')
6060
{
61-
int_vector_read(is, smallend, dim);
62-
int_vector_read(is, bigend, dim);
61+
T_vector_read(is, smallend, dim);
62+
T_vector_read(is, bigend, dim);
6363
is >> c;
6464
// Read an optional IndexType
6565
is.putback(c);
6666
if ( c == '(' )
6767
{
68-
int_vector_read(is, type, dim);
68+
T_vector_read(is, type, dim);
6969
}
7070
is.ignore(BL_IGNORE_MAX,')');
7171
}
7272
else if (c == '<')
7373
{
7474
is.putback(c);
75-
int_vector_read(is, smallend, dim);
76-
int_vector_read(is, bigend, dim);
75+
T_vector_read(is, smallend, dim);
76+
T_vector_read(is, bigend, dim);
7777
is >> c;
7878
// Read an optional IndexType
7979
is.putback(c);
8080
if ( c == '<' )
8181
{
82-
int_vector_read(is, type, dim);
82+
T_vector_read(is, type, dim);
8383
}
8484
//is.ignore(BL_IGNORE_MAX,'>');
8585
}

Src/Base/AMReX_IntVect.H

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define AMREX_INTVECT_H_
33
#include <AMReX_Config.H>
44

5+
#include <AMReX.H>
56
#include <AMReX_INT.H>
67
#include <AMReX_SPACE.H>
78
#include <AMReX_Array.H>
@@ -41,6 +42,97 @@ int coarsen (int i) noexcept
4142
return (i<0) ? -std::abs(i+1)/ratio-1 : i/ratio;
4243
}
4344

45+
/// \cond DOXYGEN_IGNORE
46+
namespace detail
47+
{
48+
template <typename T>
49+
std::ostream& T_vector_write (std::ostream& os, const T* data, int dim)
50+
{
51+
os << '(' << data[0];
52+
for (int i = 1; i < dim; ++i) {
53+
os << ',' << data[i];
54+
}
55+
os << ')';
56+
if (os.fail()) {
57+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&) failed");
58+
}
59+
return os;
60+
}
61+
62+
template <typename T>
63+
std::istream& T_vector_read (std::istream& is, T* data, int dim)
64+
{
65+
is >> std::ws;
66+
char c;
67+
is >> c;
68+
69+
for (int i = 0; i < dim; ++i) {
70+
data[i] = T(0);
71+
}
72+
73+
if (c == '(')
74+
{
75+
int component = 0;
76+
bool need_comma = false;
77+
78+
while (true) {
79+
is >> std::ws;
80+
int ic = is.peek();
81+
82+
if (ic == std::char_traits<char>::eof()) {
83+
if (component == 0) {
84+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): missing first component");
85+
} else {
86+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): premature EOF");
87+
}
88+
}
89+
90+
if (ic == static_cast<int>(')')) {
91+
is.get();
92+
if (component == 0) {
93+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): missing first component");
94+
}
95+
break;
96+
}
97+
98+
if (need_comma) {
99+
if (ic != static_cast<int>(',')) {
100+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): expected ',' or ')'");
101+
}
102+
is.get();
103+
is >> std::ws;
104+
}
105+
106+
T value{};
107+
if (!(is >> value)) {
108+
if (component == 0) {
109+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): missing first component");
110+
} else {
111+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): premature EOF");
112+
}
113+
}
114+
115+
if (component < dim) {
116+
data[component] = value;
117+
}
118+
++component;
119+
need_comma = true;
120+
}
121+
}
122+
else
123+
{
124+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&): expected '('");
125+
}
126+
127+
if (is.fail()) {
128+
amrex::Error("operator<<(ostream&,[Int|Real]Vect&) failed");
129+
}
130+
131+
return is;
132+
}
133+
}
134+
/// \endcond
135+
44136
/**
45137
* \class amrex::IntVectND
46138
* \ingroup amrex_index_space
@@ -1107,8 +1199,6 @@ Dim3 coarsen (Dim3 const& fine, IntVectND<dim> const& ratio) noexcept
11071199

11081200
/// \cond DOXYGEN_IGNORE
11091201
namespace detail {
1110-
std::ostream& int_vector_write (std::ostream& os, const int* iv, int dim);
1111-
std::istream& int_vector_read (std::istream& is, int* iv, int dim);
11121202

11131203
template<int dim>
11141204
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr
@@ -1143,18 +1233,33 @@ namespace detail {
11431233
}
11441234
/// \endcond
11451235

1236+
/**
1237+
* \brief Streams an IntVectND as a parenthesized, comma-separated tuple.
1238+
*
1239+
* The output format is `(v0,v1,...,v{dim-1})`.
1240+
*/
11461241
template<int dim>
11471242
std::ostream&
11481243
operator<< (std::ostream& os, const IntVectND<dim>& iv)
11491244
{
1150-
return detail::int_vector_write(os, iv.begin(), dim);
1245+
return detail::T_vector_write(os, iv.begin(), dim);
11511246
}
11521247

1248+
/**
1249+
* \brief Extracts an IntVectND from the canonical parenthesized tuple syntax.
1250+
*
1251+
* Accepts `(v0,v1,...,v{dim-1})` surrounded by optional whitespace.
1252+
* Missing trailing components are filled with zero, and any additional
1253+
* comma-separated values beyond `dim` are syntactically validated and then
1254+
* ignored so that higher-dimensional files are compatible with
1255+
* lower-dimensional readers. Any structural or numeric errors will result
1256+
* in `amrex::Error`.
1257+
*/
11531258
template<int dim>
11541259
std::istream&
11551260
operator>> (std::istream& is, IntVectND<dim>& iv)
11561261
{
1157-
return detail::int_vector_read(is, iv.begin(), dim);
1262+
return detail::T_vector_read(is, iv.begin(), dim);
11581263
}
11591264

11601265
/**

Src/Base/AMReX_IntVect.cpp

Lines changed: 0 additions & 68 deletions
This file was deleted.

Src/Base/AMReX_RealVect.H

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,8 +1140,6 @@ RealVectND<dim> scale (const RealVectND<dim>& p, Real s) noexcept {
11401140

11411141
/// \cond DOXYGEN_IGNORE
11421142
namespace detail {
1143-
std::ostream& real_vector_write (std::ostream& os, const Real* p, int dim);
1144-
std::istream& real_vector_read (std::istream& is, Real* p, int dim);
11451143

11461144
template<int dim>
11471145
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr
@@ -1170,18 +1168,32 @@ namespace detail {
11701168
}
11711169
/// \endcond
11721170

1171+
/**
1172+
* \brief Streams a RealVectND as a parenthesized list of comma-separated
1173+
* Real values.
1174+
*
1175+
* The output form is `(r0,r1,...,r{dim-1})`.
1176+
*/
11731177
template<int dim>
11741178
std::ostream&
11751179
operator<< (std::ostream& os, const RealVectND<dim>& p)
11761180
{
1177-
return detail::real_vector_write(os, p.begin(), dim);
1181+
return detail::T_vector_write(os, p.begin(), dim);
11781182
}
11791183

1184+
/**
1185+
* \brief Parses a RealVectND from the same `(r0,r1,...,r{dim-1})` tuple syntax.
1186+
*
1187+
* Whitespace around tokens is skipped, missing trailing entries are set to
1188+
* zero, and any additional comma-delimited values after the requested
1189+
* dimension are validated then discarded. Invalid tuple structure or
1190+
* values will raise `amrex::Error`.
1191+
*/
11801192
template<int dim>
11811193
std::istream&
11821194
operator>> (std::istream& is, RealVectND<dim>& p)
11831195
{
1184-
return detail::real_vector_read(is, p.begin(), dim);
1196+
return detail::T_vector_read(is, p.begin(), dim);
11851197
}
11861198

11871199
/**

Src/Base/AMReX_RealVect.cpp

Lines changed: 0 additions & 62 deletions
This file was deleted.

Src/Base/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ foreach(D IN LISTS AMReX_SPACEDIM)
110110
AMReX_BoxIterator.H
111111
AMReX_Dim3.H
112112
AMReX_IntVect.H
113-
AMReX_IntVect.cpp
114113
AMReX_IndexType.H
115114
AMReX_IndexType.cpp
116115
AMReX_Loop.H
@@ -123,7 +122,6 @@ foreach(D IN LISTS AMReX_SPACEDIM)
123122
AMReX_RealBox.H
124123
AMReX_RealBox.cpp
125124
AMReX_RealVect.H
126-
AMReX_RealVect.cpp
127125
# Unions of rectangle -----------------------------------------------------
128126
AMReX_BoxList.H
129127
AMReX_BoxList.cpp

0 commit comments

Comments
 (0)