Handle DARRAYs of real variables
This involves working out the code to get the base type of a select expression of a darray. Also added the runtime support for darrays with real value elements.
This commit is contained in:
parent
1326f9aef1
commit
d6efece5dd
|
|
@ -1527,7 +1527,14 @@ void NetESelect::dump(ostream&o) const
|
|||
else
|
||||
o << "(0)";
|
||||
|
||||
o << "+:" << expr_width() << "]>";
|
||||
o << "+:" << expr_width() << "]";
|
||||
if (ivl_type_t nt = net_type()) {
|
||||
o << " net_type=(" << *nt << ")";
|
||||
} else {
|
||||
o << " expr_type=" << expr_type();
|
||||
}
|
||||
|
||||
o << ">";
|
||||
}
|
||||
|
||||
void NetESFunc::dump(ostream&o) const
|
||||
|
|
|
|||
|
|
@ -2509,10 +2509,17 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Cast expression to int2" << endl;
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Cast expression to int2" << endl;
|
||||
rv = cast_to_int2(rv);
|
||||
}
|
||||
|
||||
if (lv->expr_type() == IVL_VT_REAL && rv->expr_type() != IVL_VT_REAL) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Cast expression to real." << endl;
|
||||
rv = cast_to_real(rv);
|
||||
}
|
||||
if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Enumeration type mismatch in assignment." << endl;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ static bool get_real_arg_(const NetExpr*expr, verireal&val)
|
|||
break;
|
||||
}
|
||||
|
||||
case IVL_VT_DARRAY:
|
||||
return false;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
19
net_expr.cc
19
net_expr.cc
|
|
@ -348,6 +348,25 @@ ivl_select_type_t NetESelect::select_type() const
|
|||
return sel_type_;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetESelect::expr_type() const
|
||||
{
|
||||
ivl_variable_type_t type = expr_->expr_type();
|
||||
if (type != IVL_VT_DARRAY)
|
||||
return type;
|
||||
|
||||
ivl_assert(*this, type == IVL_VT_DARRAY);
|
||||
|
||||
// Special case: If the expression is a DARRAY, then the
|
||||
// sub-expression must be a NetESignal and the type of the
|
||||
// NetESelect expression is the element type of the arrayed signal.
|
||||
NetESignal*sig = dynamic_cast<NetESignal*>(expr_);
|
||||
ivl_assert(*this, sig);
|
||||
const netarray_t*array_type = dynamic_cast<const netarray_t*> (sig->sig()->net_type());
|
||||
ivl_assert(*this, array_type);
|
||||
|
||||
return array_type->element_type()->base_type();
|
||||
}
|
||||
|
||||
bool NetESelect::has_width() const
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -3807,6 +3807,10 @@ class NetESelect : public NetExpr {
|
|||
const NetExpr*select() const;
|
||||
ivl_select_type_t select_type() const;
|
||||
|
||||
// The type of a NetESelect is the base type of the
|
||||
// sub-expression.
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool has_width() const;
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
|
|
|
|||
10
netmisc.cc
10
netmisc.cc
|
|
@ -152,6 +152,16 @@ NetExpr* cast_to_int2(NetExpr*expr)
|
|||
return cast;
|
||||
}
|
||||
|
||||
NetExpr* cast_to_real(NetExpr*expr)
|
||||
{
|
||||
if (expr->expr_type() == IVL_VT_REAL)
|
||||
return expr;
|
||||
|
||||
NetECast*cast = new NetECast('r', expr, 1, true);
|
||||
cast->set_line(*expr);
|
||||
return cast;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a signed constant to an existing expression. Generate a new
|
||||
* NetEBAdd node that has the input expression and an expression made
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid)
|
|||
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
|
||||
|
||||
extern NetExpr*cast_to_int2(NetExpr*expr);
|
||||
extern NetExpr*cast_to_real(NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Take the input expression and return a variation that assures that
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ void dll_target::expr_select(const NetESelect*net)
|
|||
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
|
||||
|
||||
expr_->type_ = IVL_EX_SELECT;
|
||||
expr_->value_= IVL_VT_VECTOR;
|
||||
expr_->value_= net->expr_type();
|
||||
expr_->net_type=0;
|
||||
expr_->width_= net->expr_width();
|
||||
expr_->signed_ = net->has_sign()? 1 : 0;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ static unsigned show_assign_lval_darray(ivl_lval_t lval, unsigned ind)
|
|||
assert(sig);
|
||||
|
||||
if (ivl_lval_idx(lval)) {
|
||||
fprintf(out, "%*sAddress-0 select of dynamic array:\n", ind+4, "");
|
||||
fprintf(out, "%*sAddress-0 select of ", ind+4, "");
|
||||
show_type_of_signal(sig);
|
||||
fprintf(out, ":\n");
|
||||
show_expression(ivl_lval_idx(lval), ind+6);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,14 +36,28 @@ static int eval_darray_new(ivl_expr_t ex)
|
|||
ivl_type_t element_type = ivl_type_element(net_type);
|
||||
assert(element_type);
|
||||
|
||||
assert(ivl_type_packed_dimensions(element_type) == 1);
|
||||
int msb = ivl_type_packed_msb(element_type, 0);
|
||||
int lsb = ivl_type_packed_lsb(element_type, 0);
|
||||
int wid = msb>=lsb? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_REAL:
|
||||
// REAL objects are not packable.
|
||||
assert(ivl_type_packed_dimensions(element_type) == 0);
|
||||
fprintf(vvp_out, " %%new/darray %u, \"r\";\n", size_reg);
|
||||
break;
|
||||
case IVL_VT_BOOL:
|
||||
// bool objects are vectorable, but for now only support
|
||||
// a single dimensions.
|
||||
assert(ivl_type_packed_dimensions(element_type) == 1);
|
||||
int msb = ivl_type_packed_msb(element_type, 0);
|
||||
int lsb = ivl_type_packed_lsb(element_type, 0);
|
||||
int wid = msb>=lsb? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
// XXXX: Assume elements are signed integers.
|
||||
fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid);
|
||||
fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,6 +306,26 @@ static int draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int draw_select_real(ivl_expr_t expr)
|
||||
{
|
||||
int res;
|
||||
/* The sube references the expression to be selected from. */
|
||||
ivl_expr_t sube = ivl_expr_oper1(expr);
|
||||
/* This is the select expression */
|
||||
ivl_expr_t shift= ivl_expr_oper2(expr);
|
||||
|
||||
/* Assume the sub-expression is a signal */
|
||||
ivl_signal_t sig = ivl_expr_signal(sube);
|
||||
assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY);
|
||||
|
||||
res = allocate_word();
|
||||
|
||||
draw_eval_expr_into_integer(shift, 3);
|
||||
fprintf(vvp_out, " %%load/dar/r %u, v%p_0;\n", res, sig);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int draw_sfunc_real(ivl_expr_t expr)
|
||||
{
|
||||
int res;
|
||||
|
|
@ -619,6 +639,10 @@ int draw_eval_real(ivl_expr_t expr)
|
|||
res = draw_realnum_real(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_SELECT:
|
||||
res = draw_select_real(expr);
|
||||
break;
|
||||
|
||||
case IVL_EX_SFUNC:
|
||||
res = draw_sfunc_real(expr);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -773,6 +773,10 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
|||
ivl_expr_t rval = ivl_stmt_rval(net);
|
||||
ivl_expr_t part = ivl_lval_part_off(lval);
|
||||
ivl_signal_t var= ivl_lval_sig(lval);
|
||||
ivl_type_t var_type= ivl_signal_net_type(var);
|
||||
assert(ivl_type_base(var_type) == IVL_VT_DARRAY);
|
||||
ivl_type_t element_type = ivl_type_element(var_type);
|
||||
|
||||
ivl_expr_t mux = ivl_lval_idx(lval);
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
|
|
@ -780,7 +784,17 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
|
|||
assert(ivl_lval_mux(lval) == 0);
|
||||
assert(part == 0);
|
||||
|
||||
if (mux) {
|
||||
if (mux && (ivl_type_base(element_type)==IVL_VT_REAL)) {
|
||||
int dst = draw_eval_real(rval);
|
||||
|
||||
/* The %set/dar expects the array index to be in index
|
||||
register 3. Calculate the index in place. */
|
||||
draw_eval_expr_into_integer(mux, 3);
|
||||
|
||||
fprintf(vvp_out, " %%set/dar/r v%p_0, %u;\n", var, dst);
|
||||
clr_word(dst);
|
||||
|
||||
} else if (mux) {
|
||||
struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval),
|
||||
STUFF_OK_XZ);
|
||||
/* The %set/dar expects the array index to be in index
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -165,6 +166,7 @@ extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_SET_AR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -170,14 +170,15 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%join/detach",of_JOIN_DETACH,1,{OA_NUMBER,OA_NONE, OA_NONE} },
|
||||
{ "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1,OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||
{ "%load/dar",of_LOAD_DAR,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/dar/r",of_LOAD_DAR_R,2,{OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%load/str",of_LOAD_STR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%load/wr",of_LOAD_WR,2, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
|
||||
{ "%load/x1p",of_LOAD_X1P,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
|
||||
{ "%loadi/wr",of_LOADI_WR,3,{OA_BIT1, OA_NUMBER, OA_BIT2} },
|
||||
|
|
@ -213,6 +214,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/dar",of_SET_DAR,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/dar/r",of_SET_DAR_R,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
|
|
|
|||
|
|
@ -598,12 +598,15 @@ out of range, then x is loaded. The index value is incremented by one
|
|||
if it is defined (bit 4 is not 1).
|
||||
|
||||
* %load/dar <bit>, <functor-label>, <wid>
|
||||
* %load/dar/r <bit>, <functor-label>
|
||||
|
||||
This instruction loads an array word from a dynamic array. The
|
||||
<label> refers to the variable object, and the <bit>/<wid> are the
|
||||
location in local vector space where the extracted word goes. The
|
||||
index is implicitly extracted from index register 3.
|
||||
|
||||
The dar/r variant reads a real-value into a real-valued register.
|
||||
|
||||
(See also %set/dar)
|
||||
|
||||
* %load/v <bit>, <functor-label>, <wid>
|
||||
|
|
@ -739,7 +742,9 @@ the array. See also %delete/obj
|
|||
|
||||
The supported types are:
|
||||
|
||||
"sb32" - signed bool 32bits
|
||||
"b<N>" - unsigned bool <N>-bits
|
||||
"sb<N>" - signed bool <N>-bits
|
||||
"r" - real
|
||||
|
||||
* %nor <dst>, <src>, <wid>
|
||||
|
||||
|
|
|
|||
|
|
@ -3124,6 +3124,29 @@ bool of_LOAD_DAR(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/dar/r <dst>, <array-label>;
|
||||
*/
|
||||
bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned dst = cp->bit_idx[0];
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
vvp_net_t*net = cp->net;
|
||||
|
||||
assert(net);
|
||||
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
|
||||
assert(obj);
|
||||
|
||||
vvp_darray*darray = dynamic_cast<vvp_darray*> (obj->get_object());
|
||||
assert(darray);
|
||||
|
||||
double word;
|
||||
darray->get_word(adr, word);
|
||||
|
||||
thr->words[dst].w_real = word;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/vp0, %load/vp0/s, %load/avp0 and %load/avp0/s share this function.
|
||||
*/
|
||||
|
|
@ -3973,6 +3996,8 @@ bool of_NEW_DARRAY(vthread_t thr, vvp_code_t cp)
|
|||
obj = new vvp_darray_atom<int32_t>(size);
|
||||
} else if (strcmp(text,"sb64") == 0) {
|
||||
obj = new vvp_darray_atom<int64_t>(size);
|
||||
} else if (strcmp(text,"r") == 0) {
|
||||
obj = new vvp_darray_real(size);
|
||||
} else {
|
||||
obj = new vvp_darray (size);
|
||||
}
|
||||
|
|
@ -4526,6 +4551,28 @@ bool of_SET_DAR(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %set/dar/r <label>, <bit>
|
||||
*/
|
||||
bool of_SET_DAR_R(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned bit = cp->bit_idx[0];
|
||||
unsigned adr = thr->words[3].w_int;
|
||||
|
||||
/* Make a vector of the desired width. */
|
||||
double value = thr->words[bit].w_real;
|
||||
|
||||
vvp_net_t*net = cp->net;
|
||||
vvp_fun_signal_object*obj = dynamic_cast<vvp_fun_signal_object*> (net->fun);
|
||||
assert(obj);
|
||||
|
||||
vvp_darray*darray = dynamic_cast<vvp_darray*>(obj->get_object());
|
||||
assert(darray);
|
||||
|
||||
darray->set_word(adr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -34,12 +34,22 @@ vvp_darray::~vvp_darray()
|
|||
|
||||
void vvp_darray::set_word(unsigned, const vvp_vector4_t&)
|
||||
{
|
||||
cerr << "XXXX set_word not implemented for " << typeid(*this).name() << endl;
|
||||
cerr << "XXXX set_word(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::set_word(unsigned, double)
|
||||
{
|
||||
cerr << "XXXX set_word(double) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::get_word(unsigned, vvp_vector4_t&)
|
||||
{
|
||||
cerr << "XXXX get_word not implemented for " << typeid(*this).name() << endl;
|
||||
cerr << "XXXX get_word(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void vvp_darray::get_word(unsigned, double&)
|
||||
{
|
||||
cerr << "XXXX get_word(double) not implemented for " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
template <class TYPE> vvp_darray_atom<TYPE>::~vvp_darray_atom()
|
||||
|
|
@ -79,3 +89,24 @@ template class vvp_darray_atom<int8_t>;
|
|||
template class vvp_darray_atom<int16_t>;
|
||||
template class vvp_darray_atom<int32_t>;
|
||||
template class vvp_darray_atom<int64_t>;
|
||||
|
||||
vvp_darray_real::~vvp_darray_real()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_darray_real::set_word(unsigned adr, double value)
|
||||
{
|
||||
if (adr >= array_.size())
|
||||
return;
|
||||
array_[adr] = value;
|
||||
}
|
||||
|
||||
void vvp_darray_real::get_word(unsigned adr, double&value)
|
||||
{
|
||||
if (adr >= array_.size()) {
|
||||
value = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
value = array_[adr];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@ class vvp_darray : public vvp_object {
|
|||
inline size_t get_size(void) const { return size_; }
|
||||
|
||||
virtual void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||
|
||||
virtual void get_word(unsigned adr, vvp_vector4_t&value);
|
||||
|
||||
virtual void set_word(unsigned adr, double value);
|
||||
virtual void get_word(unsigned adr, double&value);
|
||||
|
||||
private:
|
||||
size_t size_;
|
||||
};
|
||||
|
|
@ -54,11 +56,23 @@ template <class TYPE> class vvp_darray_atom : public vvp_darray {
|
|||
~vvp_darray_atom();
|
||||
|
||||
void set_word(unsigned adr, const vvp_vector4_t&value);
|
||||
|
||||
void get_word(unsigned adr, vvp_vector4_t&value);
|
||||
|
||||
private:
|
||||
std::vector<TYPE> array_;
|
||||
};
|
||||
|
||||
class vvp_darray_real : public vvp_darray {
|
||||
|
||||
public:
|
||||
inline vvp_darray_real(size_t siz) : vvp_darray(siz), array_(siz) { }
|
||||
~vvp_darray_real();
|
||||
|
||||
void set_word(unsigned adr, double value);
|
||||
void get_word(unsigned adr, double&value);
|
||||
|
||||
private:
|
||||
std::vector<double> array_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue