Mercurial > hg > octave-terminal
changeset 10769:569823598028
merge rewrite of structs (highegg)
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Wed, 07 Jul 2010 11:03:30 +0200 |
parents | 38bdcbb58df7 (current diff) 8a868004a437 (diff) |
children | 84c35a483d1f |
files | src/ChangeLog |
diffstat | 44 files changed, 3377 insertions(+), 860 deletions(-) [+] |
line wrap: on
line diff
--- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,8 @@ +2010-06-28 Jaroslav Hajek <highegg@gmail.com> + + * dim-vector.h (dim_vector::scalar_1x1): New method. + * lo-traits.h (equal_types): Fix. + 2010-06-21 Jaroslav Hajek <highegg@gmail.com> * Array.cc (Array<T>::cat): Implement the loose horzcat/vertcat rules
--- a/liboctave/lo-traits.h +++ b/liboctave/lo-traits.h @@ -62,7 +62,7 @@ { public: - static const bool value = false; + static const bool value = true; }; // Determine whether a type is an instance of a template.
--- a/src/Cell.h +++ b/src/Cell.h @@ -136,4 +136,8 @@ Cell map (ctype_mapper) const; }; +template<> +inline Cell octave_value_extract<Cell> (const octave_value& v) + { return v.cell_value (); } + #endif
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2010-07-07 Jaroslav Hajek <highegg@gmail.com> + + * ov-class.h (octave_class::map): Turn to octave_map. + * ov-class.cc (octave_class): Update methods. + * ov-base.h, ov-base.cc (octave_base_value::old_map_value) : Remove. + * ov.h, ov.cc (octave_value::old_map_value) : Remove. + 2010-07-06 David Bateman <dbateman@free.fr> * pr-output.cc (static bool print_eng): Flag engineering format, @@ -28,6 +35,88 @@ * DLD_FUNCTIONS/__magick_read__.cc: restore locale after GraphicsMagick initialisation. +2010-07-02 Jaroslav Hajek <highegg@gmail.com> + + * toplev.cc (octave_call_stack::do_backtrace): Use static + octave_fields struct. + (octave_call_stack::empty_backtrace): New static method. + * toplev.h: Declare it. + * error.cc (Vlast_error_stack, initialize_last_error_stack, + Frethrow): Use octave_map or octave_scalar_map where applicable. + +2010-07-02 Jaroslav Hajek <highegg@gmail.com> + + * pt-mat.cc (tm_row_const::tm_row_const_rep::all_1x1, + tm_cont::all_1x1): New member fields. + (tm_row_const::tm_row_const_rep::init, tm_const::init): + Handle them here. + (tm_row_const::all_1x1_p, tm_const::all_1x1_p): New methods. + (single_type_concat<MAP> (octave_map&, ...)): New template + overload. + (do_single_type_concat<octave_map>): New template specialization. + (tree_matrix::rvalue1): Specialize for cell and struct classes. + * oct-map.cc (octave_map::do_cat (..., const octave_map *, ...)): + Assign result dimensions. + +2010-07-02 Jaroslav Hajek <highegg@gmail.com> + + * oct-map.cc (octave_map::cat (..., const octave_scalar_map *)): + Handle special dims (-1, -2). + * data.cc (do_single_type_concat_map): Don't handle them here. + +2010-07-01 Jaroslav Hajek <highegg@gmail.com> + + * syscalls.cc (mk_stat_map, Funame): Use octave_scalar_map. + +2010-07-01 Jaroslav Hajek <highegg@gmail.com> + + * oct-map.h (octave_scalar_map::assign (const std::string&, const + octave_value&), octave_map::assign (const std::string&, const Cell&)): + Backward-compatible aliases for setfield. + +2010-07-01 Jaroslav Hajek <highegg@gmail.com> + + * oct-map.cc (octave_fields::equal_up_to_order (const octave_fields&, + octave_idx_type *)): New overload. + (octave_fields::equal_up_to_order (const octave_fields&, + Array<octave_idx_type>&)): Use it here. + (octave_map::fast_elem_insert, + octave_map::fast_elem_extract): New methods. + * oct-map.h: Update decls. + * ov-struct.cc (octave_struct::fast_elem_extract, + octave_struct::fast_elem_insert, + octave_scalar_struct::fast_elem_insert_self): New methods. + * ov-struct.h: Update decls. + +2010-06-28 Jaroslav Hajek <highegg@gmail.com> + + * data.cc (single_type_concat): Optimize all scalars case where + applicable. + (single_type_concat_map, do_single_type_concat_map): New funcs. + * pt-mat.cc (get_concat_class): Handle cell and struct concats. + + +2010-06-25 Jaroslav Hajek <highegg@gmail.com> + + * DLD-FUNCTIONS/cellfun.cc (Fnum2cell, do_num2cell): Optimize cells + and structs. + +2010-06-25 Jaroslav Hajek <highegg@gmail.com> + + * ov-struct.h (octave_scalar_struct::resize, octave_struct::resize): + Don't ignore fill argument. + +2010-06-25 Jaroslav Hajek <highegg@gmail.com> + + * oct-map.h (octave_map::octave_map (const dim_vector&, const + octave_fields&)): New internal ctor. + + * oct-map.cc (octave_map::assign): Handle no fields case. + +2010-06-25 Jaroslav Hajek <highegg@gmail.com> + + * ov-struct.cc (Fcell2struct): Rewrite. + 2010-06-30 Jaroslav Hajek <highegg@gmail.com> * ov-range.cc (octave_range::save_ascii): Save length rather than @@ -49,6 +138,23 @@ * octave.cc: Add [FILE] to octave usage string (bug #30258). +2010-06-24 Jaroslav Hajek <highegg@gmail.com> + + * oct-map.h (octave_map, octave_scalar_map): New classes. + * oct-map.cc (octave_map, octave_scalar_map): Implement them. + (Octave_map::Octave_map (const octave_map&)): New ctor. + * ov-struct.h (octave_struct): Use octave_map for storage. + (octave_scalar_struct): New class. + * ov-struct.cc: Update implementations. + * ov-base.h (octave_base_value::old_map_value): New method. + (octave_base_value::map_value): Return octave_map. + (octave_base_value::scalar_map_value): New method. + * ov-base.cc (octave_base_value::old_map_value, + octave_base_value::map_value, octave_base_value::scalar_map_value): + Add default implementations. + * ov-class.h (octave_class::old_map_value): New override. + * ov-class.cc: Use old_map_value for efficiency. + 2010-06-23 David Bateman <dbateman@free.fr> * graphics.cc (void root_figure::reset_default_properties (void),
--- a/src/DLD-FUNCTIONS/cellfun.cc +++ b/src/DLD-FUNCTIONS/cellfun.cc @@ -906,6 +906,16 @@ } template<class NDA> +static inline typename NDA::element_type +do_num2cell_elem (const NDA& array, octave_idx_type i) +{ return array(i); } + +static inline Cell +do_num2cell_elem (const Cell& array, octave_idx_type i) +{ return Cell (array(i)); } + + +template<class NDA> static Cell do_num2cell (const NDA& array, const Array<int>& dimv) { @@ -914,7 +924,7 @@ Cell retval (array.dims ()); octave_idx_type nel = array.numel (); for (octave_idx_type i = 0; i < nel; i++) - retval.xelem (i) = array(i); + retval.xelem (i) = do_num2cell_elem (array, i); return retval; } @@ -1030,34 +1040,10 @@ retval = do_num2cell (array.array_value (), dimv); } } - else if (array.is_cell () || array.is_map ()) - { - dim_vector celldv, arraydv; - Array<int> perm; - do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm); - - if (! error_state) - { - // FIXME: this operation may be rather inefficient. - octave_value parray = array.permute (perm); - - octave_idx_type nela = arraydv.numel (), nelc = celldv.numel (); - parray = parray.reshape (dim_vector (nela, nelc)); - - Cell retcell (celldv); - octave_value_list idx (2); - idx(0) = octave_value::magic_colon_t; - - for (octave_idx_type i = 0; i < nelc; i++) - { - idx(1) = i + 1; - octave_value tmp = parray.do_index_op (idx); - retcell(i) = tmp.reshape (arraydv); - } - - retval = retcell; - } - } + else if (array.is_map ()) + retval = do_num2cell (array.map_value (), dimv); + else if (array.is_cell ()) + retval = do_num2cell (array.cell_value (), dimv); else gripe_wrong_type_arg ("num2cell", array); }
--- a/src/DLD-FUNCTIONS/onCleanup.cc +++ b/src/DLD-FUNCTIONS/onCleanup.cc @@ -58,7 +58,10 @@ bool is_object (void) const { return true; } // do we want this? - Octave_map map_value (void) const; + octave_map map_value (void) const + { return scalar_map_value (); } + + octave_scalar_map scalar_map_value (void) const; dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; } @@ -169,11 +172,11 @@ } } -Octave_map -octave_oncleanup::map_value (void) const +octave_scalar_map +octave_oncleanup::scalar_map_value (void) const { - Octave_map retval; - retval.assign ("task", fcn); + octave_scalar_map retval; + retval.setfield ("task", fcn); return retval; }
--- a/src/data.cc +++ b/src/data.cc @@ -1369,6 +1369,17 @@ */ +static bool +all_scalar_1x1 (const octave_value_list& args) +{ + int n_args = args.length (); + for (int i = 0; i < n_args; i++) + if (args(i).numel () != 1) + return false; + + return true; +} + template <class TYPE, class T> static void single_type_concat (Array<T>& result, @@ -1376,17 +1387,41 @@ int dim) { int n_args = args.length (); - OCTAVE_LOCAL_BUFFER (Array<T>, array_list, n_args); - - for (int j = 0; j < n_args && ! error_state; j++) + if (! (equal_types<T, char>::value + || equal_types<T, octave_value>::value) + && all_scalar_1x1 (args)) { - octave_quit (); - - array_list[j] = octave_value_extract<TYPE> (args(j)); + // Optimize all scalars case. + dim_vector dv (1, 1); + if (dim == -1 || dim == -2) + dim = -dim - 1; + else if (dim >= 2) + dv.resize (dim+1, 1); + dv(dim) = n_args; + + result.clear (dv); + + for (int j = 0; j < n_args && ! error_state; j++) + { + octave_quit (); + + result(j) = octave_value_extract<T> (args(j)); + } } - - if (! error_state) - result = Array<T>::cat (dim, n_args, array_list); + else + { + OCTAVE_LOCAL_BUFFER (Array<T>, array_list, n_args); + + for (int j = 0; j < n_args && ! error_state; j++) + { + octave_quit (); + + array_list[j] = octave_value_extract<TYPE> (args(j)); + } + + if (! error_state) + result = Array<T>::cat (dim, n_args, array_list); + } } template <class TYPE, class T> @@ -1421,6 +1456,39 @@ return result; } +template<class MAP> +static void +single_type_concat_map (octave_map& result, + const octave_value_list& args, + int dim) +{ + int n_args = args.length (); + OCTAVE_LOCAL_BUFFER (MAP, map_list, n_args); + + for (int j = 0; j < n_args && ! error_state; j++) + { + octave_quit (); + + map_list[j] = octave_value_extract<MAP> (args(j)); + } + + if (! error_state) + result = octave_map::cat (dim, n_args, map_list); +} + +static octave_map +do_single_type_concat_map (const octave_value_list& args, + int dim) +{ + octave_map result; + if (all_scalar_1x1 (args)) // optimize all scalars case. + single_type_concat_map<octave_scalar_map> (result, args, dim); + else + single_type_concat_map<octave_map> (result, args, dim); + + return result; +} + static octave_value do_cat (const octave_value_list& args, int dim, std::string fname) { @@ -1514,6 +1582,10 @@ retval = do_single_type_concat<uint32NDArray> (args, dim); else if (result_type == "uint64") retval = do_single_type_concat<uint64NDArray> (args, dim); + else if (result_type == "cell") + retval = do_single_type_concat<Cell> (args, dim); + else if (result_type == "struct") + retval = do_single_type_concat_map (args, dim); else { dim_vector dv = args(0).dims ();
--- a/src/error.cc +++ b/src/error.cc @@ -87,7 +87,7 @@ static std::string Vlast_error_id; // The last file in which an error occured -static Octave_map Vlast_error_stack; +static octave_map Vlast_error_stack; // Current error state. // @@ -141,24 +141,10 @@ warning_options.assign ("state", state); } -static Octave_map +static octave_map initialize_last_error_stack (void) { - static bool initialized = false; - - static string_vector sv (4); - - if (! initialized) - { - sv[0] = "file"; - sv[1] = "name"; - sv[2] = "line"; - sv[3] = "column"; - - initialized = true; - } - - return Octave_map (dim_vector (0, 1), sv); + return octave_call_stack::empty_backtrace (); } // Warning messages are never buffered. @@ -867,14 +853,14 @@ print_usage (); else { - Octave_map err = args(0).map_value (); + const octave_scalar_map err = args(0).scalar_map_value (); if (! error_state) { if (err.contains ("message") && err.contains ("identifier")) { - std::string msg = err.contents("message")(0).string_value (); - std::string id = err.contents("identifier")(0).string_value (); + std::string msg = err.contents("message").string_value (); + std::string id = err.contents("identifier").string_value (); int len = msg.length(); std::string file; @@ -882,11 +868,11 @@ int l = -1; int c = -1; - Octave_map err_stack = initialize_last_error_stack (); + octave_map err_stack = initialize_last_error_stack (); if (err.contains ("stack")) { - err_stack = err.contents("stack")(0).map_value (); + err_stack = err.contents("stack").map_value (); if (err_stack.numel () > 0) {
--- a/src/oct-map.cc +++ b/src/oct-map.cc @@ -2,6 +2,7 @@ Copyright (C) 1995, 1996, 1997, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton +Copyright (C) 2010 VZLU Prague This file is part of Octave. @@ -31,6 +32,1202 @@ #include "oct-map.h" #include "utils.h" +octave_fields::fields_rep octave_fields::nil_rep; + +octave_fields::octave_fields (const string_vector& fields) + : rep (new fields_rep) +{ + octave_idx_type n = fields.numel (); + for (octave_idx_type i = 0; i < n; i++) + (*rep)[fields(i)] = i; +} + +octave_fields::octave_fields (const char * const *fields) + : rep (new fields_rep) +{ + octave_idx_type n = 0; + while (*fields) + (*rep)[std::string (*fields++)] = n++; +} + +bool +octave_fields::isfield (const std::string& field) const +{ + return rep->find (field) != rep->end (); +} + +octave_idx_type +octave_fields::getfield (const std::string& field) const +{ + fields_rep::iterator p = rep->find (field); + return (p != rep->end ()) ? p->second : -1; +} + +octave_idx_type +octave_fields::getfield (const std::string& field) +{ + fields_rep::iterator p = rep->find (field); + if (p != rep->end ()) + return p->second; + else + { + make_unique (); + octave_idx_type n = rep->size (); + return (*rep)[field] = n; + } +} + +octave_idx_type +octave_fields::rmfield (const std::string& field) +{ + fields_rep::iterator p = rep->find (field); + if (p == rep->end ()) + return -1; + else + { + octave_idx_type n = p->second; + make_unique (); + rep->erase (field); + for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) + { + if (q->second >= n) + q->second--; + } + + return n; + } +} + +void +octave_fields::orderfields (Array<octave_idx_type>& perm) +{ + octave_idx_type n = rep->size (); + perm.clear (n, 1); + + make_unique (); + octave_idx_type i = 0; + for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) + { + octave_idx_type j = q->second; + q->second = i; + perm(i++) = j; + } +} + +bool +octave_fields::equal_up_to_order (const octave_fields& other, + octave_idx_type* perm) const +{ + bool retval = true; + + iterator p = begin (), q = other.begin (); + for (; p != end () && q != other.end (); p++, q++) + { + if (p->first == q->first) + perm[p->second] = q->second; + else + { + retval = false; + break; + } + } + + retval = (p == end () && q == other.end ()); + + return retval; +} + +bool +octave_fields::equal_up_to_order (const octave_fields& other, + Array<octave_idx_type>& perm) const +{ + octave_idx_type n = nfields (); + if (perm.length () != n) + perm.clear (1, n); + + return equal_up_to_order (other, perm.fortran_vec ()); +} + +string_vector +octave_fields::fieldnames (void) const +{ + octave_idx_type n = nfields (); + string_vector retval(n); + + for (iterator p = begin (); p != end (); p++) + retval.xelem(p->second) = p->first; + + return retval; +} + +octave_value +octave_scalar_map::getfield (const std::string& k) const +{ + octave_idx_type idx = xkeys.getfield (k); + return (idx >= 0) ? xvals[idx] : octave_value (); +} + +void +octave_scalar_map::setfield (const std::string& k, const octave_value& val) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx < static_cast<octave_idx_type> (xvals.size ())) + xvals[idx] = val; + else + xvals.push_back (val); +} + +void +octave_scalar_map::rmfield (const std::string& k) +{ + octave_idx_type idx = xkeys.rmfield (k); + if (idx >= 0) + xvals.erase (xvals.begin () + idx); +} + +octave_scalar_map +octave_scalar_map::orderfields (void) const +{ + Array<octave_idx_type> perm; + return orderfields (perm); +} + +octave_scalar_map +octave_scalar_map::orderfields (Array<octave_idx_type>& perm) const +{ + octave_scalar_map retval (xkeys); + retval.xkeys.orderfields (perm); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem(i)]; + + return retval; +} + +octave_scalar_map +octave_scalar_map::orderfields (const octave_scalar_map& other, + Array<octave_idx_type>& perm) const +{ + if (xkeys.is_same (other.xkeys)) + return *this; + else + { + octave_scalar_map retval (other.xkeys); + if (other.xkeys.equal_up_to_order (xkeys, perm)) + { + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem(i)]; + } + else + error ("orderfields: structs must have same fields up to order"); + + return retval; + } +} + +octave_value +octave_scalar_map::contents (const std::string& k) const +{ + return getfield (k); +} + +octave_value& +octave_scalar_map::contents (const std::string& k) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx >= static_cast<octave_idx_type> (xvals.size ())) + xvals.resize (idx); + return xvals[idx]; +} + +octave_map::octave_map (const octave_scalar_map& m) + : xkeys (m.xkeys), xvals (), dimensions (1, 1) +{ + octave_idx_type nf = m.nfields (); + xvals.reserve (nf); + for (octave_idx_type i = 0; i < nf; i++) + { + xvals.push_back (Cell (dimensions)); + xvals[i].xelem(0) = m.xvals[i]; + } +} + +octave_map::octave_map (const Octave_map& m) + : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ()) +{ + for (iterator p = begin (); p != end (); p++) + contents(p) = m.contents (key (p)); + + optimize_dimensions (); +} + +Cell +octave_map::getfield (const std::string& k) const +{ + octave_idx_type idx = xkeys.getfield (k); + return (idx >= 0) ? xvals[idx] : Cell (); +} + +void +octave_map::setfield (const std::string& k, const Cell& val) +{ + if (nfields () == 0) + dimensions = val.dims (); + + if (val.dims () == dimensions) + { + octave_idx_type idx = xkeys.getfield (k); + if (idx < static_cast<octave_idx_type> (xvals.size ())) + xvals[idx] = val; + else + xvals.push_back (val); + } + else + error ("octave_map::setfield: internal error"); +} + +void +octave_map::rmfield (const std::string& k) +{ + octave_idx_type idx = xkeys.rmfield (k); + if (idx >= 0) + xvals.erase (xvals.begin () + idx); +} + +octave_map +octave_map::orderfields (void) const +{ + Array<octave_idx_type> perm; + return orderfields (perm); +} + +octave_map +octave_map::orderfields (Array<octave_idx_type>& perm) const +{ + octave_map retval (xkeys); + retval.xkeys.orderfields (perm); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem(i)]; + + return retval; +} + +octave_map +octave_map::orderfields (const octave_map& other, + Array<octave_idx_type>& perm) const +{ + if (xkeys.is_same (other.xkeys)) + return *this; + else + { + octave_map retval (other.xkeys); + if (other.xkeys.equal_up_to_order (xkeys, perm)) + { + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem(i)]; + } + else + error ("orderfields: structs must have same fields up to order"); + + return retval; + } +} + +Cell +octave_map::contents (const std::string& k) const +{ + return getfield (k); +} + +Cell& +octave_map::contents (const std::string& k) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx >= static_cast<octave_idx_type> (xvals.size ())) + xvals.push_back (Cell (dimensions)); // auto-set correct dims. + return xvals[idx]; +} + +void +octave_map::extract_scalar (octave_scalar_map& dest, + octave_idx_type idx) const +{ + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + dest.xvals[i] = xvals[i](idx); +} + +octave_scalar_map +octave_map::checkelem (octave_idx_type n) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (n, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::checkelem (octave_idx_type i, octave_idx_type j) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (i, j, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::checkelem (const Array<octave_idx_type>& ra_idx) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (ra_idx, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::fast_elem_extract (octave_idx_type n) const +{ + octave_scalar_map retval (xkeys); + + extract_scalar (retval, n); + + return retval; +} + +bool +octave_map::fast_elem_insert (octave_idx_type n, + const octave_scalar_map& rhs) +{ + bool retval = false; + + octave_idx_type nf = nfields (); + if (rhs.xkeys.is_same (xkeys)) + { + for (octave_idx_type i = 0; i < nf; i++) + xvals[i](n) = rhs.xvals[i]; + + retval = true; + } + else + { + OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, nf); + if (xkeys.equal_up_to_order (rhs.xkeys, perm)) + { + for (octave_idx_type i = 0; i < nf; i++) + xvals[i](n) = rhs.xvals[perm[i]]; + + retval = true; + } + } + + return retval; +} + +octave_map +octave_map::squeeze (void) const +{ + octave_map retval (*this); + octave_idx_type nf = nfields (); + + retval.dimensions = dimensions.squeeze (); + + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].squeeze (); + + retval.optimize_dimensions (); + + return retval; +} + +/* +%!# test preservation of xkeys by squeeze +%!test +%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; +%! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::permute (const Array<int>& vec, bool inv) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].permute (vec, inv); + + // FIXME: + // There is no dim_vector::permute for technical reasons. + // We pick the dim vector from results if possible, otherwise use a dummy + // array to get it. Need (?) a better solution to this problem. + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + Array<char> dummy (dimensions); + dummy = dummy.permute (vec, inv); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +/* +%!# test preservation of key order by permute +%!test +%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; +%! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::transpose (void) const +{ + assert (ndims () == 2); + + octave_map retval (xkeys); + + retval.dimensions = dim_vector (dimensions (1), dimensions (0)); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].transpose (); + + retval.optimize_dimensions (); + + return retval; +} + +/* +%!# test preservation of key order by transpose +%!test +%! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27; +%! assert (fieldnames (transpose (x)), {"d"; "a"; "f"}); +%! assert (fieldnames (x'), {"d"; "a"; "f"}); +%! assert (fieldnames (x.'), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::reshape (const dim_vector& dv) const +{ + octave_map retval (xkeys); + retval.dimensions = dv; + + octave_idx_type nf = nfields (); + if (nf > 0) + { + retval.xvals.reserve (nf); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].reshape (dv); + } + else + { + // FIXME: Do it with a dummy array, to reuse error message. + // Need (?) a better solution. + Array<char> dummy (dimensions); + dummy.reshape (dv); + } + + retval.optimize_dimensions (); + + return retval; +} + +/* +%!# test preservation of key order by reshape +%!test +%! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27; +%! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"}); +*/ + +void +octave_map::resize (const dim_vector& dv, bool fill) +{ + octave_idx_type nf = nfields (); + if (nf > 0) + { + for (octave_idx_type i = 0; i < nf; i++) + { + if (fill) + xvals[i].resize (dv, Cell::resize_fill_value ()); + else + xvals[i].resize (dv); + } + } + else + { + // FIXME: Do it with a dummy array, to reuse error message. + // Need (?) a better solution. + Array<char> dummy (dimensions); + dummy.resize (dv); + } + + dimensions = dv; + optimize_dimensions (); +} + +void +octave_map::do_cat (int dim, octave_idx_type n, const octave_scalar_map *map_list, + octave_map& retval) +{ + octave_idx_type nf = retval.nfields (); + retval.xvals.reserve (nf); + + dim_vector& rd = retval.dimensions; + rd.resize (dim+1, 1); + rd(0) = rd(1) = 1; + rd(dim) = n; + + for (octave_idx_type j = 0; j < nf; j++) + { + retval.xvals.push_back (Cell (rd)); + assert (retval.xvals[j].numel () == n); + for (octave_idx_type i = 0; i < n; i++) + retval.xvals[j].xelem(i) = map_list[i].xvals[j]; + } +} + +void +octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list, + octave_map& retval) +{ + octave_idx_type nf = retval.nfields (); + retval.xvals.reserve (nf); + + OCTAVE_LOCAL_BUFFER (Array<octave_value>, field_list, n); + + for (octave_idx_type j = 0; j < nf; j++) + { + for (octave_idx_type i = 0; i < n; i++) + field_list[i] = map_list[i].xvals[j]; + + retval.xvals.push_back (Array<octave_value>::cat (dim, n, field_list)); + if (j == 0) + retval.dimensions = retval.xvals[j].dims (); + } +} + +template <class map> +static void +permute_to_correct_order (octave_idx_type n, octave_idx_type nf, + const map *map_list, map *new_map_list) +{ + new_map_list[0] = map_list[0]; + + Array<octave_idx_type> perm (1, nf); + + for (octave_idx_type i = 1; i < n; i++) + { + new_map_list[i] = map_list[i].orderfields (map_list[0], perm); + + if (error_state) + { + // Use liboctave exception to be consistent. + (*current_liboctave_error_handler) + ("cat: field names mismatch in concatenating structs"); + break; + } + } +} + + +octave_map +octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list) +{ + octave_map retval; + // Allow dim = -1, -2 for compatibility, though it makes no difference here. + if (dim == -1 || dim == -2) + dim = -dim - 1; + else if (dim < 0) + (*current_liboctave_error_handler) + ("cat: invalid dimension"); + + if (n > 0) + { + retval.xkeys = map_list[0].xkeys; + octave_idx_type nf = map_list[0].nfields (); + if (nf > 0) + { + // Try the fast case. + bool all_same = true; + for (octave_idx_type i = 1; i < n; i++) + { + all_same = map_list[0].xkeys.is_same (map_list[i].xkeys); + if (! all_same) + break; + } + + if (all_same) + do_cat (dim, n, map_list, retval); + else + { + // permute all structures to common order. + OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n); + + permute_to_correct_order (n, nf, map_list, new_map_list); + + do_cat (dim, n, new_map_list, retval); + } + + } + else + { + dim_vector& rd = retval.dimensions; + rd.resize (dim+1, 1); + rd(0) = rd(1) = 1; + rd(dim) = n; + } + + retval.optimize_dimensions (); + } + + return retval; +} + +octave_map +octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list) +{ + octave_map retval; + if (n > 0) + { + retval.xkeys = map_list[0].xkeys; + octave_idx_type nf = map_list[0].nfields (); + + // Try the fast case. + bool all_same = true; + for (octave_idx_type i = 1; i < n; i++) + { + all_same = map_list[0].xkeys.is_same (map_list[i].xkeys); + if (! all_same) + break; + } + + if (all_same) + do_cat (dim, n, map_list, retval); + else + { + // permute all structures to correct order. + OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n); + + permute_to_correct_order (n, nf, map_list, new_map_list); + + if (nf > 0) + do_cat (dim, n, new_map_list, retval); + else + { + // Use dummy arrays. FIXME: Need(?) a better solution. + OCTAVE_LOCAL_BUFFER (Array<char>, dummy, n); + for (octave_idx_type i = 0; i < n; i++) + dummy[i].clear (map_list[0].dimensions); + Array<char>::cat (dim, n, dummy); + } + } + + retval.optimize_dimensions (); + } + + return retval; +} + +/* +%!# test preservation of key order by concatenation +%!test +%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; +%! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33; +%! assert (fieldnames ([x; y]), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::index (const idx_vector& i, bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (i, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy = dummy.index (i, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const idx_vector& i, const idx_vector& j, + bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (i, j, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy = dummy.index (i, j, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (ia, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy = dummy.index (ia, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const octave_value_list& idx, bool resize_ok) const +{ + octave_idx_type n_idx = idx.length (); + octave_map retval; + + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + retval = index (i, resize_ok); + } + break; + + case 2: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + idx_vector j = idx(1).index_vector (); + + retval = index (i, j, resize_ok); + } + } + break; + + default: + { + Array<idx_vector> ia (n_idx, 1); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + retval = index (ia, resize_ok); + } + break; + } + + return retval; +} + +// Perhaps one day these will be optimized. Right now, they just call index. +octave_map +octave_map::column (octave_idx_type k) const +{ + return index (idx_vector::colon, k); +} + +octave_map +octave_map::page (octave_idx_type k) const +{ + static Array<idx_vector> ia (3, 1, idx_vector::colon); + + ia(2) = k; + return index (ia); +} + +void +octave_map::assign (const idx_vector& i, const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (i, rhs.xvals[k]); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (i, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (i, rhs); + *this = tmp; + } + else + { + Array<octave_idx_type> perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (i, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const idx_vector& i, const idx_vector& j, + const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (i, j, rhs.xvals[k]); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (i, j, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (i, j, rhs); + *this = tmp; + } + else + { + Array<octave_idx_type> perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (i, j, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const Array<idx_vector>& ia, + const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (ia, rhs.xvals[k]); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (ia, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (ia, rhs); + *this = tmp; + } + else + { + Array<octave_idx_type> perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (ia, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const octave_value_list& idx, const octave_map& rhs) +{ + octave_idx_type n_idx = idx.length (); + + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + assign (i, rhs); + } + break; + + case 2: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + idx_vector j = idx(1).index_vector (); + + assign (i, j, rhs); + } + } + break; + + default: + { + Array<idx_vector> ia (n_idx, 1); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + assign (ia, rhs); + } + break; + } +} + +void +octave_map::assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs) +{ + Cell tmp; + iterator p = seek (k); + Cell& ref = p != end () ? contents (p) : tmp; + + if (&ref == &tmp) + ref = Cell (dimensions); + + ref.assign (idx, rhs); + + if (! error_state && ref.dims () != dimensions) + { + dimensions = ref.dims (); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + { + if (&xvals[i] != &ref) + xvals[i].resize (dimensions, Cell::resize_fill_value ()); + } + + optimize_dimensions (); + } + + if (! error_state && &ref == &tmp) + setfield (k, tmp); +} + +void +octave_map::delete_elements (const idx_vector& i) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (i); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy.delete_elements (i); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (int dim, const idx_vector& i) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (dim, i); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy.delete_elements (dim, i); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (const Array<idx_vector>& ia) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (ia); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array<char> dummy (dimensions); + dummy.delete_elements (ia); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (const octave_value_list& idx) +{ + octave_idx_type n_idx = idx.length (); + + Array<idx_vector> ia (n_idx, 1); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + delete_elements (ia); +} + +/* +%!# test preservation of key order by indexing +%!test +%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; +%! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::concat (const octave_map& rb, const Array<octave_idx_type>& ra_idx) +{ + if (nfields () == rb.nfields ()) + { + for (const_iterator pa = begin (); pa != end (); pa++) + { + const_iterator pb = rb.seek (key(pa)); + + if (pb == rb.end ()) + { + error ("field name mismatch in structure concatenation"); + break; + } + + contents(pa).insert (rb.contents(pb), ra_idx); + } + } + else + { + dim_vector dv = dims (); + + if (dv.all_zero ()) + *this = rb; + else if (! rb.dims ().all_zero ()) + error ("invalid structure concatenation"); + } + + return *this; +} + +void +octave_map::optimize_dimensions (void) +{ + octave_idx_type nf = nfields (); + + for (octave_idx_type i = 0; i < nf; i++) + { + if (! xvals[i].optimize_dimensions (dimensions)) + { + error ("internal error: dimension mismatch across fields in struct"); + break; + } + } + +} + Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals) : map (), key_list (), dimensions (dv) { @@ -49,6 +1246,16 @@ error ("Octave_map: expecting keys to be cellstr"); } +Octave_map::Octave_map (const octave_map& m) + : map (), key_list (), dimensions (m.dims ()) +{ + for (octave_map::const_iterator p = m.begin (); p != m.end (); p++) + map[m.key (p)] = m.contents (p); + const string_vector mkeys = m.fieldnames (); + for (octave_idx_type i = 0; i < mkeys.numel (); i++) + key_list.push_back (mkeys(i)); +} + Octave_map Octave_map::squeeze (void) const { @@ -70,13 +1277,6 @@ return retval; } -/* -%!# test preservation of keys by squeeze -%!test -%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; -%! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"}); -*/ - Octave_map Octave_map::permute (const Array<int>& vec, bool inv) const { @@ -98,13 +1298,6 @@ return retval; } -/* -%!# test preservation of key order by permute -%!test -%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; -%! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"}); -*/ - Cell& Octave_map::contents (const std::string& k) { @@ -179,15 +1372,6 @@ return retval; } -/* -%!# test preservation of key order by transpose -%!test -%! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27; -%! assert (fieldnames (transpose (x)), {"d"; "a"; "f"}); -%! assert (fieldnames (x'), {"d"; "a"; "f"}); -%! assert (fieldnames (x.'), {"d"; "a"; "f"}); -*/ - Octave_map Octave_map::reshape (const dim_vector& new_dims) const { @@ -209,13 +1393,6 @@ return retval; } -/* -%!# test preservation of key order by reshape -%!test -%! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27; -%! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"}); -*/ - void Octave_map::resize (const dim_vector& dv, bool fill) { @@ -286,14 +1463,6 @@ return retval; } -/* -%!# test preservation of key order by concatenation -%!test -%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; -%! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33; -%! assert (fieldnames ([x; y]), {"d"; "a"; "f"}); -*/ - static bool keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys) { @@ -526,10 +1695,3 @@ return retval; } - -/* -%!# test preservation of key order by indexing -%!test -%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; -%! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"}); -*/
--- a/src/oct-map.h +++ b/src/oct-map.h @@ -2,6 +2,7 @@ Copyright (C) 1994, 1995, 1996, 1997, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2009 John W. Eaton +Copyright (C) 2010 VZLU Prague This file is part of Octave. @@ -32,6 +33,442 @@ class string_vector; +// A class holding a map field->index. Supports reference-counting. +class OCTINTERP_API +octave_fields +{ + class fields_rep : public std::map<std::string, octave_idx_type> + { + public: + fields_rep (void) : std::map<std::string, octave_idx_type> (), count (1) { } + fields_rep (const fields_rep& other) + : std::map<std::string, octave_idx_type> (other), count (1) { } + + int count; + + private: + fields_rep& operator = (const fields_rep&); // no assignment! + }; + + fields_rep *rep; + + static fields_rep nil_rep; + +public: + + octave_fields (void) : rep (&nil_rep) { rep->count++; } + octave_fields (const string_vector&); + octave_fields (const char * const *); + + ~octave_fields (void) + { + if (--rep->count == 0) + delete rep; + } + + void make_unique (void) + { + if (rep->count > 1) + { + --rep->count; + rep = new fields_rep (*rep); + } + } + + octave_fields (const octave_fields& o) : rep (o.rep) { rep->count++; } + + octave_fields& + operator = (const octave_fields& o) + { + o.rep->count++; + if (--rep->count == 0) + delete rep; + rep = o.rep; + + return *this; + } + + // constant iteration support. non-const iteration intentionally unsupported. + + typedef std::map<std::string, octave_idx_type>::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return rep->begin (); } + const_iterator end (void) const { return rep->end (); } + + std::string key (const_iterator p) const { return p->first; } + octave_idx_type index (const_iterator p) const { return p->second; } + + const_iterator seek (const std::string& k) const + { return rep->find (k); } + + // high-level methods. + + // number of fields. + octave_idx_type nfields (void) const { return rep->size (); } + + // check whether a field exists. + bool isfield (const std::string& name) const; + + // get index of field. return -1 if not exist + octave_idx_type getfield (const std::string& name) const; + // get index of field. add if not exist + octave_idx_type getfield (const std::string& name); + // remove field and return the index. -1 if didn't exist. + octave_idx_type rmfield (const std::string& name); + + // order the fields of this map. creates a permutation + // used to order the fields. + void orderfields (Array<octave_idx_type>& perm); + + // compares two instances for equality up to order of fields. + // returns a permutation needed to bring the fields of *other* + // into the order of *this*. + bool equal_up_to_order (const octave_fields& other, + octave_idx_type* perm) const; + + bool equal_up_to_order (const octave_fields& other, + Array<octave_idx_type>& perm) const; + + bool is_same (const octave_fields& other) const + { return rep == other.rep; } + + // Returns the fields as a vector of strings. + string_vector fieldnames (void) const; + + void clear (void) + { + *this = octave_fields (); + } +}; + + +class OCTINTERP_API +octave_scalar_map +{ +public: + + octave_scalar_map (const octave_fields& k) + : xkeys (k), xvals (k.nfields ()) { } + + octave_scalar_map (void) : xkeys (), xvals () { } + + octave_scalar_map (const string_vector& k) + : xkeys (k), xvals (k.length ()) { } + + octave_scalar_map (const octave_scalar_map& m) + : xkeys (m.xkeys), xvals(m.xvals) { } + + octave_scalar_map& operator = (const octave_scalar_map& m) + { + xkeys = m.xkeys; + xvals = m.xvals; + + return *this; + } + + // iteration support. note that both const and non-const iterators are the + // same. The const/non-const distinction is made by the key & contents method. + typedef octave_fields::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return xkeys.begin (); } + const_iterator end (void) const { return xkeys.end (); } + + const_iterator seek (const std::string& k) const { return xkeys.seek (k); } + + std::string key (const_iterator p) const + { return xkeys.key (p); } + octave_idx_type index (const_iterator p) const + { return xkeys.index (p); } + + const octave_value& contents (const_iterator p) const + { return xvals[xkeys.index (p)]; } + + octave_value& contents (iterator p) + { return xvals[xkeys.index (p)]; } + + const octave_value& contents (octave_idx_type i) const + { return xvals[i]; } + + octave_value& contents (octave_idx_type i) + { return xvals[i]; } + + // number of fields. + octave_idx_type nfields (void) const { return xkeys.nfields (); } + + // check whether a field exists. + bool isfield (const std::string& name) const + { return xkeys.isfield (name); } + + bool contains (const std::string& name) const + { return isfield (name); } + + string_vector fieldnames (void) const + { return xkeys.fieldnames (); } + + string_vector keys (void) const + { return fieldnames (); } + + // get contents of a given field. empty value if not exist. + octave_value getfield (const std::string& key) const; + + // set contents of a given field. add if not exist. + void setfield (const std::string& key, const octave_value& val); + void assign (const std::string& k, const octave_value& val) + { setfield (k, val); } + + // remove a given field. do nothing if not exist. + void rmfield (const std::string& key); + void del (const std::string& k) { rmfield (k); } + + // return a copy with fields ordered, optionally along with permutation. + octave_scalar_map orderfields (void) const; + octave_scalar_map orderfields (Array<octave_idx_type>& perm) const; + octave_scalar_map orderfields (const octave_scalar_map& other, + Array<octave_idx_type>& perm) const; + + // aka getfield/setfield, but the latter returns a reference. + octave_value contents (const std::string& k) const; + octave_value& contents (const std::string& k); + + void clear (void) + { + xkeys.clear (); + xvals.clear (); + } + + friend class octave_map; + +private: + + octave_fields xkeys; + std::vector<octave_value> xvals; + +}; + +template<> +inline octave_scalar_map octave_value_extract<octave_scalar_map> (const octave_value& v) + { return v.scalar_map_value (); } + +class OCTINTERP_API +octave_map +{ +public: + + octave_map (const octave_fields& k) + : xkeys (k), xvals (k.nfields ()), dimensions () { } + + octave_map (const dim_vector& dv, const octave_fields& k) + : xkeys (k), xvals (k.nfields (), Cell (dv)), dimensions (dv) { } + + typedef octave_scalar_map element_type; + + octave_map (void) : xkeys (), xvals (), dimensions () { } + + octave_map (const dim_vector& dv) : xkeys (), xvals (), dimensions (dv) { } + + octave_map (const string_vector& k) + : xkeys (k), xvals (k.length ()), dimensions (1, 1) { } + + octave_map (const dim_vector& dv, const string_vector& k) + : xkeys (k), xvals (k.length (), Cell (dv)), dimensions (dv) { } + + octave_map (const octave_map& m) + : xkeys (m.xkeys), xvals (m.xvals), dimensions (m.dimensions) { } + + octave_map (const octave_scalar_map& m); + + octave_map (const Octave_map& m); + + octave_map& operator = (const octave_map& m) + { + xkeys = m.xkeys; + xvals = m.xvals; + dimensions = m.dimensions; + + return *this; + } + + // iteration support. note that both const and non-const iterators are the + // same. The const/non-const distinction is made by the key & contents method. + typedef octave_fields::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return xkeys.begin (); } + const_iterator end (void) const { return xkeys.end (); } + + const_iterator seek (const std::string& k) const { return xkeys.seek (k); } + + std::string key (const_iterator p) const + { return xkeys.key (p); } + octave_idx_type index (const_iterator p) const + { return xkeys.index (p); } + + const Cell& contents (const_iterator p) const + { return xvals[xkeys.index (p)]; } + + Cell& contents (iterator p) + { return xvals[xkeys.index (p)]; } + + const Cell& contents (octave_idx_type i) const + { return xvals[i]; } + + Cell& contents (octave_idx_type i) + { return xvals[i]; } + + // number of fields. + octave_idx_type nfields (void) const { return xkeys.nfields (); } + + // check whether a field exists. + bool isfield (const std::string& name) const + { return xkeys.isfield (name); } + + bool contains (const std::string& name) const + { return isfield (name); } + + string_vector fieldnames (void) const + { return xkeys.fieldnames (); } + + string_vector keys (void) const + { return fieldnames (); } + + // get contents of a given field. empty value if not exist. + Cell getfield (const std::string& key) const; + + // set contents of a given field. add if not exist. checks for + // correct dimensions. + void setfield (const std::string& key, const Cell& val); + void assign (const std::string& k, const Cell& val) + { setfield (k, val); } + + // remove a given field. do nothing if not exist. + void rmfield (const std::string& key); + void del (const std::string& k) { rmfield (k); } + + // return a copy with fields ordered, optionally along with permutation. + octave_map orderfields (void) const; + octave_map orderfields (Array<octave_idx_type>& perm) const; + octave_map orderfields (const octave_map& other, + Array<octave_idx_type>& perm) const; + + // aka getfield/setfield, but the latter returns a reference. + Cell contents (const std::string& k) const; + Cell& contents (const std::string& k); + + void clear (void) + { + xkeys.clear (); + xvals.clear (); + } + + // The Array-like methods. + octave_idx_type numel (void) const { return dimensions.numel (); } + octave_idx_type length (void) const { return numel (); } + bool is_empty (void) const { return dimensions.any_zero (); } + + octave_idx_type rows (void) const { return dimensions(0); } + octave_idx_type cols (void) const { return dimensions(1); } + octave_idx_type columns (void) const { return dimensions(1); } + + // Extract a scalar substructure. + octave_scalar_map checkelem (octave_idx_type n) const; + octave_scalar_map checkelem (octave_idx_type i, octave_idx_type j) const; + + octave_scalar_map + checkelem (const Array<octave_idx_type>& ra_idx) const; + + octave_scalar_map operator () (octave_idx_type n) const + { return checkelem (n); } + octave_scalar_map operator () (octave_idx_type i, octave_idx_type j) const + { return checkelem (i, j); } + + octave_scalar_map + operator () (const Array<octave_idx_type>& ra_idx) const + { return checkelem (ra_idx); } + + octave_map squeeze (void) const; + + octave_map permute (const Array<int>& vec, bool inv = false) const; + + dim_vector dims (void) const { return dimensions; } + + int ndims (void) const { return dimensions.length (); } + + octave_map transpose (void) const; + + octave_map reshape (const dim_vector& dv) const; + + void resize (const dim_vector& dv, bool fill = false); + + static octave_map + cat (int dim, octave_idx_type n, const octave_scalar_map *map_list); + + static octave_map + cat (int dim, octave_idx_type n, const octave_map *map_list); + + octave_map index (const idx_vector& i, bool resize_ok = false) const; + + octave_map index (const idx_vector& i, const idx_vector& j, + bool resize_ok = false) const; + + octave_map index (const Array<idx_vector>& ia, + bool resize_ok = false) const; + + octave_map index (const octave_value_list&, bool resize_ok = false) const; + + octave_map column (octave_idx_type k) const; + octave_map page (octave_idx_type k) const; + + void assign (const idx_vector& i, const octave_map& rhs); + + void assign (const idx_vector& i, const idx_vector& j, const octave_map& rhs); + + void assign (const Array<idx_vector>& ia, const octave_map& rhs); + + void assign (const octave_value_list&, const octave_map& rhs); + + void assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs); + + void delete_elements (const idx_vector& i); + + void delete_elements (int dim, const idx_vector& i); + + void delete_elements (const Array<idx_vector>& ia); + + void delete_elements (const octave_value_list&); + + octave_map concat (const octave_map& rb, const Array<octave_idx_type>& ra_idx); + + // like checkelem, but no check. + octave_scalar_map fast_elem_extract (octave_idx_type n) const; + + // element assignment, no bounds check + bool fast_elem_insert (octave_idx_type n, const octave_scalar_map& rhs); + +private: + + octave_fields xkeys; + std::vector<Cell> xvals; + dim_vector dimensions; + + void optimize_dimensions (void); + void extract_scalar (octave_scalar_map& dest, + octave_idx_type index) const; + static void do_cat (int dim, octave_idx_type n, + const octave_scalar_map *map_list, octave_map& retval); + static void do_cat (int dim, octave_idx_type n, + const octave_map *map_list, octave_map& retval); +}; + +template<> +inline octave_map octave_value_extract<octave_map> (const octave_value& v) + { return v.map_value (); } + +// The original Octave_map object. Octave_map and octave_map are convertible to +// each other. + class OCTINTERP_API Octave_map @@ -85,6 +522,8 @@ Octave_map (const Octave_map& m) : map (m.map), key_list (m.key_list), dimensions (m.dimensions) { } + Octave_map (const octave_map& m); + Octave_map& operator = (const Octave_map& m) { if (this != &m)
--- a/src/ov-base-mat.h +++ b/src/ov-base-mat.h @@ -39,8 +39,6 @@ #include "ov-base.h" #include "ov-typeinfo.h" -class Octave_map; - class tree_walker; // Real matrix values.
--- a/src/ov-base-sparse.h +++ b/src/ov-base-sparse.h @@ -39,8 +39,6 @@ #include "boolSparse.h" #include "MatrixType.h" -class Octave_map; - class tree_walker; class octave_sparse_bool_matrix;
--- a/src/ov-base.cc +++ b/src/ov-base.cc @@ -885,14 +885,30 @@ return retval; } -Octave_map +octave_map octave_base_value::map_value (void) const { - Octave_map retval; + octave_map retval; gripe_wrong_type_arg ("octave_base_value::map_value()", type_name ()); return retval; } +octave_scalar_map +octave_base_value::scalar_map_value (void) const +{ + octave_map tmp = map_value (); + + if (tmp.numel () == 1) + return tmp.checkelem (0); + else + { + if (! error_state) + error ("invalid conversion of multidimensional struct to scalar struct"); + + return octave_scalar_map (); + } +} + string_vector octave_base_value::map_keys (void) const {
--- a/src/ov-base.h +++ b/src/ov-base.h @@ -42,6 +42,8 @@ class Cell; class Octave_map; +class octave_map; +class octave_scalar_map; class octave_value; class octave_value_list; class octave_stream; @@ -542,7 +544,9 @@ virtual Range range_value (void) const; - virtual Octave_map map_value (void) const; + virtual octave_map map_value (void) const; + + virtual octave_scalar_map scalar_map_value (void) const; virtual string_vector map_keys (void) const;
--- a/src/ov-bool-mat.h +++ b/src/ov-bool-mat.h @@ -42,7 +42,6 @@ #include "MatrixType.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-bool-sparse.h +++ b/src/ov-bool-sparse.h @@ -42,7 +42,6 @@ #include "ov-base-sparse.h" #include "ov-re-sparse.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-bool.h +++ b/src/ov-bool.h @@ -41,7 +41,6 @@ #include "ov-scalar.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-cell.h +++ b/src/ov-cell.h @@ -40,7 +40,6 @@ #include "ov-base-mat.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-ch-mat.h +++ b/src/ov-ch-mat.h @@ -41,7 +41,6 @@ #include "ov-re-mat.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-class.cc +++ b/src/ov-class.cc @@ -66,7 +66,7 @@ (octave_class::t_name, "<unknown>", octave_value (new octave_class ())); } -octave_class::octave_class (const Octave_map& m, const std::string& id, +octave_class::octave_class (const octave_map& m, const std::string& id, const octave_value_list& parents) : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { @@ -231,7 +231,7 @@ } } - Octave_map m; + octave_map m; m.assign ("type", type_field); m.assign ("subs", subs_field); @@ -259,7 +259,7 @@ octave_base_value *obvp = method_class.empty () ? 0 : find_parent_class (method_class); - Octave_map my_map; + octave_map my_map; my_map = obvp ? obvp->map_value () : map; @@ -267,7 +267,7 @@ if (! error_state) { - Octave_map::const_iterator p = my_map.seek (nm); + octave_map::const_iterator p = my_map.seek (nm); if (p != my_map.end ()) retval = my_map.contents (p); @@ -486,7 +486,7 @@ retval = val(0); if (type.length () > 0 && type[0] == '.' && ! retval.is_map ()) - retval = Octave_map (); + retval = octave_map (); } else gripe_invalid_index_for_assignment (); @@ -646,11 +646,11 @@ std::string next_type = type.substr (1); Cell tmpc (1, 1); - Octave_map::iterator pkey = map.seek (key); + octave_map::iterator pkey = map.seek (key); if (pkey != map.end ()) { - pkey->second.make_unique (); - tmpc = pkey->second; + map.contents (pkey).make_unique (); + tmpc = map.contents (pkey); } // FIXME: better code reuse? @@ -721,7 +721,7 @@ { if (t_rhs.is_object () || t_rhs.is_map ()) { - Octave_map rhs_map = t_rhs.map_value (); + octave_map rhs_map = t_rhs.map_value (); if (! error_state) { @@ -742,7 +742,7 @@ { if (t_rhs.is_empty ()) { - map.maybe_delete_elements (idx.front()); + map.delete_elements (idx.front()); if (! error_state) { @@ -851,7 +851,7 @@ size_t retval = 0; - for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) + for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) { std::string key = map.key (p); @@ -884,9 +884,9 @@ pit != parent_list.end (); pit++) { - Octave_map::const_iterator smap = map.seek (*pit); + octave_map::const_iterator smap = map.seek (*pit); - const Cell& tmp = smap->second; + const Cell& tmp = map.contents (smap); octave_value vtmp = tmp(0); @@ -915,9 +915,9 @@ pit != parent_list.end (); pit++) { - Octave_map::iterator smap = map.seek (*pit); + octave_map::iterator smap = map.seek (*pit); - Cell& tmp = smap->second; + Cell& tmp = map.contents (smap); octave_value& vtmp = tmp(0); @@ -1053,7 +1053,7 @@ std::string dbgstr = "dork"; // First, check to see if there might be an issue with inheritance. - for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) + for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) { std::string key = map.key (p); Cell val = map.contents (p); @@ -1102,7 +1102,7 @@ octave_class::save_ascii (std::ostream& os) { os << "# classname: " << class_name () << "\n"; - Octave_map m; + octave_map m; if (load_path::find_method (class_name (), "saveobj") != std::string ()) { octave_value in = new octave_class (*this); @@ -1117,7 +1117,7 @@ os << "# length: " << m.nfields () << "\n"; - Octave_map::iterator i = m.begin (); + octave_map::iterator i = m.begin (); while (i != m.end ()) { octave_value val = map.contents (i); @@ -1146,7 +1146,7 @@ { if (len > 0) { - Octave_map m (map); + octave_map m (map); for (octave_idx_type j = 0; j < len; j++) { @@ -1203,7 +1203,7 @@ } else if (len == 0 ) { - map = Octave_map (dim_vector (1, 1)); + map = octave_map (dim_vector (1, 1)); c_name = classname; } else @@ -1232,7 +1232,7 @@ os.write (reinterpret_cast<char *> (&classname_len), 4); os << class_name (); - Octave_map m; + octave_map m; if (load_path::find_method (class_name (), "saveobj") != std::string ()) { octave_value in = new octave_class (*this); @@ -1248,7 +1248,7 @@ int32_t len = m.nfields(); os.write (reinterpret_cast<char *> (&len), 4); - Octave_map::iterator i = m.begin (); + octave_map::iterator i = m.begin (); while (i != m.end ()) { octave_value val = map.contents (i); @@ -1295,7 +1295,7 @@ if (len > 0) { - Octave_map m (map); + octave_map m (map); for (octave_idx_type j = 0; j < len; j++) { @@ -1348,7 +1348,7 @@ } } else if (len == 0 ) - map = Octave_map (dim_vector (1, 1)); + map = octave_map (dim_vector (1, 1)); else panic_impossible (); @@ -1366,8 +1366,8 @@ hid_t space_hid = -1; hid_t class_hid = -1; hid_t data_hid = -1; - Octave_map m; - Octave_map::iterator i; + octave_map m; + octave_map::iterator i; #if HAVE_HDF5_18 group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); @@ -1468,7 +1468,7 @@ hdf5_callback_data dsub; herr_t retval2 = 0; - Octave_map m (dim_vector (1, 1)); + octave_map m (dim_vector (1, 1)); int current_item = 0; hsize_t num_obj = 0; int slen = 0; @@ -1624,7 +1624,7 @@ { if (obj.is_object ()) { - Octave_map m = obj.map_value (); + octave_map m = obj.map_value (); field_names = m.keys (); parent_class_names = obj.parent_class_name_list (); @@ -1646,7 +1646,7 @@ { if (nfields () == obj.nfields ()) { - Octave_map obj_map = obj.map_value (); + octave_map obj_map = obj.map_value (); string_vector obj_fnames = obj_map.keys (); string_vector fnames = fields (); @@ -1725,7 +1725,7 @@ if (fcn && fcn->is_class_constructor ()) { - Octave_map m = args(0).map_value (); + octave_map m = args(0).map_value (); if (! error_state) {
--- a/src/ov-class.h +++ b/src/ov-class.h @@ -52,14 +52,14 @@ octave_class (void) : octave_base_value (), obsolete_copies (0) { } - octave_class (const Octave_map& m, const std::string& id) + octave_class (const octave_map& m, const std::string& id) : octave_base_value (), map (m), c_name (id), obsolete_copies (0) { } octave_class (const octave_class& s) : octave_base_value (s), map (s.map), c_name (s.c_name), parent_list (s.parent_list), obsolete_copies (0) { } - octave_class (const Octave_map& m, const std::string& id, + octave_class (const octave_map& m, const std::string& id, const octave_value_list& parents); ~octave_class (void) { } @@ -70,7 +70,7 @@ octave_base_value *empty_clone (void) const { - return new octave_class (Octave_map (map.keys ()), class_name ()); + return new octave_class (octave_map (map.keys ()), class_name ()); } Cell dotref (const octave_value_list& idx); @@ -122,7 +122,7 @@ { return map.reshape (new_dims); } octave_value resize (const dim_vector& dv, bool = false) const - { Octave_map tmap = map; tmap.resize (dv); return tmap; } + { octave_map tmap = map; tmap.resize (dv); return tmap; } bool is_defined (void) const { return true; } @@ -130,7 +130,7 @@ bool is_object (void) const { return true; } - Octave_map map_value (void) const { return map; } + octave_map map_value (void) const { return map; } string_vector map_keys (void) const; @@ -178,7 +178,7 @@ private: - Octave_map map; + octave_map map; DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-colon.h +++ b/src/ov-colon.h @@ -36,7 +36,6 @@ #include "ov-base.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-complex.h +++ b/src/ov-complex.h @@ -41,7 +41,6 @@ #include "ov-base-scalar.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-cx-mat.h +++ b/src/ov-cx-mat.h @@ -42,7 +42,6 @@ #include "MatrixType.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-cx-sparse.h +++ b/src/ov-cx-sparse.h @@ -42,7 +42,6 @@ #include "ov-base-sparse.h" #include "ov-re-sparse.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-fcn-inline.cc +++ b/src/ov-fcn-inline.cc @@ -117,7 +117,7 @@ // This function is supplied to allow a Matlab style class structure // to be returned.. -Octave_map +octave_map octave_fcn_inline::map_value (void) const { Octave_map m;
--- a/src/ov-fcn-inline.h +++ b/src/ov-fcn-inline.h @@ -67,7 +67,7 @@ octave_value convert_to_str_internal (bool, bool, char) const; - Octave_map map_value (void) const; + octave_map map_value (void) const; bool save_ascii (std::ostream& os);
--- a/src/ov-float.h +++ b/src/ov-float.h @@ -43,7 +43,6 @@ #include "ov-base-scalar.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-flt-complex.h +++ b/src/ov-flt-complex.h @@ -41,7 +41,6 @@ #include "ov-base-scalar.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-flt-cx-mat.h +++ b/src/ov-flt-cx-mat.h @@ -42,7 +42,6 @@ #include "MatrixType.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-flt-re-mat.h +++ b/src/ov-flt-re-mat.h @@ -42,7 +42,6 @@ #include "MatrixType.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-range.h +++ b/src/ov-range.h @@ -43,7 +43,6 @@ #include "ov-re-mat.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-re-mat.h +++ b/src/ov-re-mat.h @@ -42,7 +42,6 @@ #include "MatrixType.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-re-sparse.h +++ b/src/ov-re-sparse.h @@ -43,7 +43,6 @@ #include "ov-base-sparse.h" #include "ov-cx-sparse.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-scalar.h +++ b/src/ov-scalar.h @@ -42,7 +42,6 @@ #include "ov-base-scalar.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-str-mat.h +++ b/src/ov-str-mat.h @@ -40,7 +40,6 @@ #include "ov-re-mat.h" #include "ov-typeinfo.h" -class Octave_map; class octave_value_list; class tree_walker;
--- a/src/ov-struct.cc +++ b/src/ov-struct.cc @@ -51,6 +51,17 @@ DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct"); +octave_base_value * +octave_struct::try_narrowing_conversion (void) +{ + octave_base_value *retval = 0; + + if (numel () == 1) + retval = new octave_scalar_struct (map.checkelem (0)); + + return retval; +} + Cell octave_struct::dotref (const octave_value_list& idx, bool auto_add) { @@ -60,7 +71,7 @@ std::string nm = idx(0).string_value (); - Octave_map::const_iterator p = map.seek (nm); + octave_map::const_iterator p = map.seek (nm); if (p != map.end ()) retval = map.contents (p); @@ -131,7 +142,7 @@ } } else - retval(0) = map.index (idx.front ()); + retval(0) = do_index_op (idx.front ()); } break; @@ -197,7 +208,7 @@ } } else - retval = map.index (idx.front (), auto_add); + retval = do_index_op (idx.front (), auto_add); } break; @@ -245,7 +256,7 @@ octave_value retval; if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) - retval = Octave_map (); + retval = octave_map (); else retval = val; @@ -297,11 +308,11 @@ std::string next_type = type.substr (2); Cell tmpc (1, 1); - Octave_map::iterator pkey = map.seek (key); + octave_map::iterator pkey = map.seek (key); if (pkey != map.end ()) { - pkey->second.make_unique (); - tmpc = pkey->second.index (idx.front (), true); + map.contents (pkey).make_unique (); + tmpc = map.contents (pkey).index (idx.front (), true); } // FIXME: better code reuse? cf. octave_cell::subsasgn and the case below. @@ -347,11 +358,11 @@ std::string next_type = type.substr (1); Cell tmpc (1, 1); - Octave_map::iterator pkey = map.seek (key); + octave_map::iterator pkey = map.seek (key); if (pkey != map.end ()) { - pkey->second.make_unique (); - tmpc = pkey->second; + map.contents (pkey).make_unique (); + tmpc = map.contents (pkey); } // FIXME: better code reuse? @@ -432,12 +443,12 @@ } else { - const Octave_map& cmap = const_cast<const Octave_map &> (map); + const octave_map& cmap = const_cast<const octave_map &> (map); // cast map to const reference to avoid forced key insertion. if (idxf.all_scalars () || cmap.contents (key).index (idxf, true).numel () == 1) { - map.assign (idxf, key, t_rhs.storable_value ()); + map.assign (idxf, key, Cell (t_rhs.storable_value ())); if (! error_state) { count++; @@ -457,7 +468,7 @@ { if (t_rhs.is_map()) { - Octave_map rhs_map = t_rhs.map_value (); + octave_map rhs_map = t_rhs.map_value (); if (! error_state) { @@ -478,7 +489,7 @@ { if (t_rhs.is_null_value()) { - map.maybe_delete_elements (idx.front()); + map.delete_elements (idx.front()); if (! error_state) { @@ -514,11 +525,14 @@ if (numel () == tmp_cell.numel ()) tmp_cell = tmp_cell.reshape (dims ()); - map.assign (key, tmp_cell); + map.setfield (key, tmp_cell); } else - // Regularize a null matrix if stored into a struct component. - map.assign (key, t_rhs.storable_value ()); + { + Cell tmp_cell(1, 1); + tmp_cell(0) = t_rhs.storable_value (); + map.setfield (key, tmp_cell); + } if (! error_state) { @@ -541,13 +555,15 @@ else gripe_failed_assignment (); + retval.maybe_mutate (); + return retval; } octave_value octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok) { - // Octave_map handles indexing itself. + // octave_map handles indexing itself. return map.index (idx, resize_ok); } @@ -558,7 +574,7 @@ size_t retval = 0; - for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) + for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) { std::string key = map.key (p); @@ -606,7 +622,7 @@ increment_indent_level (); } - string_vector key_list = map.keys (); + string_vector key_list = map.fieldnames (); for (octave_idx_type i = 0; i < key_list.length (); i++) { @@ -693,619 +709,10 @@ %!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs"); */ -DEFUN (struct, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\ -\n\ -Create a structure and initialize its value.\n\ -\n\ -If the values are cell arrays, create a structure array and initialize\n\ -its values. The dimensions of each cell array of values must match.\n\ -Singleton cells and non-cell values are repeated so that they fill\n\ -the entire array. If the cells are empty, create an empty structure\n\ -array with the specified field names.\n\ -\n\ -If the argument is an object, return the underlying struct.\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - // struct ([]) returns an empty struct. - - // struct (empty_matrix) returns an empty struct with the same - // dimensions as the empty matrix. - - // Note that struct () creates a 1x1 struct with no fields for - // compatibility with Matlab. - - if (nargin == 1 && args(0).is_object ()) - { - Octave_map m = args(0).map_value (); - retval = octave_value (new octave_struct (m)); - - return retval; - } - - if ((nargin == 1 || nargin == 2) - && args(0).is_empty () && args(0).is_real_matrix ()) - { - Cell fields; - - if (nargin == 2) - { - if (args(1).is_cellstr ()) - retval = Octave_map (args(0).dims (), args(1).cell_value ()); - else - error ("struct: expecting cell array of field names as second argument"); - } - else - retval = Octave_map (args(0).dims ()); - - return retval; - } - - // Check for "field", VALUE pairs. - - for (int i = 0; i < nargin; i += 2) - { - if (! args(i).is_string () || i + 1 >= nargin) - { - error ("struct expects alternating \"field\", VALUE pairs"); - return retval; - } - } - - // Check that the dimensions of the values correspond. - - dim_vector dims (1, 1); - - int first_dimensioned_value = 0; - - for (int i = 1; i < nargin; i += 2) - { - if (args(i).is_cell ()) - { - dim_vector argdims (args(i).dims ()); - - if (! scalar (argdims)) - { - if (! first_dimensioned_value) - { - dims = argdims; - first_dimensioned_value = i + 1; - } - else if (dims != argdims) - { - error ("struct: dimensions of parameter %d do not match those of parameter %d", - first_dimensioned_value, i+1); - return retval; - } - } - } - } - - // Create the return value. - - Octave_map map (dims); - - for (int i = 0; i < nargin; i+= 2) - { - // Get key. - - std::string key (args(i).string_value ()); - - if (error_state) - return retval; - - if (! valid_identifier (key)) - { - error ("struct: invalid structure field name `%s'", key.c_str ()); - return retval; - } - - // Value may be v, { v }, or { v1, v2, ... } - // In the first two cases, we need to create a cell array of - // the appropriate dimensions filled with v. In the last case, - // the cell array has already been determined to be of the - // correct dimensions. - - if (args(i+1).is_cell ()) - { - const Cell c (args(i+1).cell_value ()); - - if (error_state) - return retval; - - if (scalar (c.dims ())) - map.assign (key, Cell (dims, c(0))); - else - map.assign (key, c); - } - else - map.assign (key, Cell (dims, args(i+1))); - - if (error_state) - return retval; - } - - return octave_value (map); -} - -DEFUN (isstruct, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\ -Return 1 if the value of the expression @var{expr} is a structure\n\ -(or a structure array).\n\ -@end deftypefn") -{ - octave_value retval; - - if (args.length () == 1) - retval = args(0).is_map (); - else - print_usage (); - - return retval; -} - -DEFUN (fieldnames, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\ -Return a cell array of strings naming the elements of the structure\n\ -@var{struct}. It is an error to call @code{fieldnames} with an\n\ -argument that is not a structure.\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 1) - { - octave_value arg = args(0); - - if (arg.is_map () || arg.is_object ()) - { - Octave_map m = arg.map_value (); - - string_vector keys = m.keys (); - - if (keys.length () == 0) - retval = Cell (0, 1); - else - retval = Cell (m.keys ()); - } - else - gripe_wrong_type_arg ("fieldnames", args(0)); - } - else - print_usage (); - - return retval; -} - -/* -%!# test preservation of fieldname order -%!test -%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; -%! assert(fieldnames(x), {"d"; "a"; "b"; "c"}); -*/ - -DEFUN (isfield, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\ -Return true if the expression @var{expr} is a structure and it\n\ -includes an element named @var{name}. If @var{name} is a cell\n\ -array, a logical array of equal dimension is returned.\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 2) - { - retval = false; - - if (args(0).is_map ()) - { - Octave_map m = args(0).map_value (); - - // FIXME -- should this work for all types that can do - // structure reference operations? - - if (args(1).is_string ()) - { - std::string key = args(1).string_value (); - - retval = m.contains (key) != 0; - } - else if (args(1).is_cell ()) - { - Cell c = args(1).cell_value (); - boolMatrix bm (c.dims ()); - octave_idx_type n = bm.numel (); - - for (octave_idx_type i = 0; i < n; i++) - { - if (c(i).is_string ()) - { - std::string key = c(i).string_value (); - - bm(i) = m.contains (key) != 0; - } - else - bm(i) = false; - } - - retval = bm; - } - } - } - else - print_usage (); - - return retval; -} - -DEFUN (nfields, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} nfields (@var{s})\n\ -Return the number of fields of the structure @var{s}.\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 1 && args(0).is_map ()) - { - retval = static_cast<double> (args(0).nfields ()); - } - else - print_usage (); - - return retval; -} - -/* -%!# test isfield -%!test -%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; -%! assert (isfield (x, "b")); -%!assert( isfield( struct("a", "1"), "a")); -%!assert( isfield( {1}, "c"), logical (0)); -%!assert( isfield( struct("a", "1"), 10), logical (0)); -%!assert( isfield( struct("a", "b"), "a "), logical (0)); - -*/ - -// Check that the dimensions of the input arguments are correct. - -static bool -cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv, - bool is_cell, int dim) -{ - bool retval = true; - - if (dim >= 0 && dim < c_dv.length ()) - { - if (is_cell) - { - if (f_dv.numel () != c_dv(dim)) - { - error ("cell2struct: numel (FIELD) != size (CELL, DIM)"); - - retval = false; - } - } - else - { - if (f_dv.length () > 2) - { - error ("cell2struct: field array must be a 2-d matrix"); - - retval = false; - } - else if (f_dv(0) != c_dv(dim)) - { - error ("cell2struct: size (FIELD, 1) != length (C, DIM)"); - - retval = false; - } - } - } - else - { - error ("cell2struct: DIM out of range"); - - retval = false; - } - - return retval; -} - -static void -cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1, - const Array<octave_idx_type>& ra_idx2, - octave_idx_type dim, octave_idx_type fill_value) -{ - octave_idx_type iidx = 0; - - for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++) - { - if (idx == dim) - ra_idx1.elem (idx) = fill_value; - else - ra_idx1.elem (idx) = ra_idx2(iidx++); - } -} - -DEFUN (cell2struct, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\ -Convert @var{cell} to a structure. The number of fields in @var{fields}\n\ -must match the number of elements in @var{cell} along dimension @var{dim},\n\ -that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\ -\n\ -@example\n\ -@group\n\ -A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\ - 185, 170, 168@},\n\ - @{'Name','Height'@}, 1);\n\ -A(1)\n\ - @result{} ans =\n\ - @{\n\ - Name = Peter\n\ - Height = 185\n\ - @}\n\ -\n\ -@end group\n\ -@end example\n\ -@end deftypefn") -{ - octave_value retval; - - if (args.length () == 3) - { - Cell c = args(0).cell_value (); - - if (! error_state) - { - octave_value field = args(1); - - // Field is either cell or character matrix. - - // FIXME -- this could be simplified if we had - // cellstr and iscellstr functions available. - - bool field_is_cell = field.is_cell (); - - Cell field_cell; - charMatrix field_char; - - if (field_is_cell) - field_cell = field.cell_value (); - else - field_char = field.char_matrix_value (); - - if (! error_state) - { - // Retrieve the dimension value. - - // FIXME -- int_value () should print out the - // conversions it does to be Matlab compatible. - - octave_idx_type dim = args(2).int_value () - 1; - - if (! error_state) - { - dim_vector c_dv = c.dims (); - dim_vector field_dv = field.dims (); - - if (cell2struct_check_args (c_dv, field_dv, field_is_cell, - dim)) - { - octave_idx_type c_dv_length = c_dv.length (); - - // Dimension vector for the Cell arrays to be - // put into the structure. - - dim_vector value_dv; - - // Initialize c_value_dv. - - if (c_dv_length == 2) - value_dv = dim_vector (1, 1); - else - value_dv.resize (c_dv_length - 1); - - octave_idx_type idx_tmp = 0; - - for (octave_idx_type i = 0; i < c_dv_length; i++) - { - if (i != dim) - value_dv.elem (idx_tmp++) = c_dv.elem (i); - } - - // All initializing is done, we can start moving - // values. - - Octave_map map; - - // If field is a cell array then we use all - // elements in array, on the other hand when - // field is a character array the number of - // elements is equals the number of rows. - - octave_idx_type field_numel - = field_is_cell ? field_dv.numel (): field_dv(0); - - // For matlab compatibility. - - if (field_numel == 0) - map.reshape (dim_vector (0, 1)); - - for (octave_idx_type i = 0; i < field_numel; i++) - { - // Construct cell array which goes into the - // structure together with the appropriate - // field name. - - Cell c_value (value_dv); - - Array<octave_idx_type> value_idx (value_dv.length (), 1, 0); - Array<octave_idx_type> c_idx (c_dv_length, 1, 0); - - for (octave_idx_type j = 0; j < value_dv.numel (); j++) - { - // Need to do this to construct the - // appropriate idx for getting elements - // from the original cell array. - - cell2struct_construct_idx (c_idx, value_idx, - dim, i); - - c_value.elem (value_idx) = c.elem (c_idx); - - increment_index (value_idx, value_dv); - } - - std::string field_str; - - if (field_is_cell) - { - // Matlab retrieves the field values - // column by column. - - octave_value field_tmp = field_cell.elem (i); - - field_str = field_tmp.string_value (); - - if (error_state) - { - error ("cell2struct: fields have to be of type string"); - break; - } - } - else - { - field_str = field_char.row_as_string (i); - - if (error_state) - return retval; - } - - if (! valid_identifier (field_str)) - { - error ("cell2struct: invalid field name `%s'", - field_str.c_str ()); - break; - } - - map.reshape (value_dv); - - map.assign (field_str, c_value); - } - - if (! error_state) - retval = map; - } - } - else - error ("cell2struct: expecting third argument to be an integer"); - } - else - error ("cell2struct: expecting second argument to be a cell or character array"); - } - else - error ("cell2struct: expecting first argument to be a cell array"); - } - else - print_usage (); - - return retval; -} - -/* -%!# test cell2struct versus struct2cell -%!test -%! keys = cellstr (char (floor (rand (100,10)*24+65)))'; -%! vals = mat2cell(rand (100,1), ones (100,1), 1)'; -%! s = struct ([keys; vals]{:}); -%! t = cell2struct (vals, keys, 2); -%! assert (s, t); -%! assert (struct2cell (s), vals'); -%! assert (fieldnames (s), keys'); -*/ - - -// So we can call Fcellstr directly. -extern octave_value_list Fcellstr (const octave_value_list& args, int); - -DEFUN (rmfield, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\ -Return a copy of the structure (array) @var{s} with the field @var{f} removed.\n\ -If @var{f} is a cell array of strings or a character array, remove the\n\ -named fields.\n\ -@seealso{cellstr, iscellstr, setfield}\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 2) - { - Octave_map m = args(0).map_value (); - - octave_value_list fval = Fcellstr (args(1), 1); - - if (! error_state) - { - Cell fcell = fval(0).cell_value (); - - for (int i = 0; i < fcell.numel (); i++) - { - std::string key = fcell(i).string_value (); - - if (m.contains (key)) - m.del (key); - else - { - error ("rmfield: structure does not contain field %s", - key.c_str ()); - - break; - } - } - - if (! error_state) - retval = m; - } - } - else - print_usage (); - - return retval; -} - -/* -%!# test rmfield -%!test -%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123"; -%! y = rmfield (x, {"a", "f"}); -%! assert (fieldnames (y), {"d"; "b"; "c"}); -%! assert (size (y), [1, 6]); -*/ - bool octave_struct::save_ascii (std::ostream& os) { - Octave_map m = map_value (); + octave_map m = map_value (); octave_idx_type nf = m.nfields (); @@ -1321,7 +728,7 @@ // Iterating over the list of keys will preserve the order of the // fields. - string_vector keys = m.keys (); + string_vector keys = m.fieldnames (); for (octave_idx_type i = 0; i < nf; i++) { @@ -1374,7 +781,7 @@ { if (len > 0) { - Octave_map m (dv); + octave_map m (dv); for (octave_idx_type j = 0; j < len; j++) { @@ -1396,7 +803,7 @@ return false; } - m.assign (nm, tcell); + m.setfield (nm, tcell); } if (is) @@ -1408,7 +815,7 @@ } } else if (len == 0 ) - map = Octave_map (dv); + map = octave_map (dv); else panic_impossible (); } @@ -1423,7 +830,7 @@ bool octave_struct::save_binary (std::ostream& os, bool& save_as_floats) { - Octave_map m = map_value (); + octave_map m = map_value (); octave_idx_type nf = m.nfields (); @@ -1445,7 +852,7 @@ // Iterating over the list of keys will preserve the order of the // fields. - string_vector keys = m.keys (); + string_vector keys = m.fieldnames (); for (octave_idx_type i = 0; i < nf; i++) { @@ -1500,7 +907,7 @@ if (len > 0) { - Octave_map m (dv); + octave_map m (dv); for (octave_idx_type j = 0; j < len; j++) { @@ -1523,7 +930,7 @@ return false; } - m.assign (nm, tcell); + m.setfield (nm, tcell); } if (is) @@ -1535,7 +942,7 @@ } } else if (len == 0) - map = Octave_map (dv); + map = octave_map (dv); else success = false; @@ -1557,13 +964,13 @@ if (data_hid < 0) return false; // recursively add each element of the structure to this group - Octave_map m = map_value (); + octave_map m = map_value (); octave_idx_type nf = m.nfields (); // Iterating over the list of keys will preserve the order of the // fields. - string_vector keys = m.keys (); + string_vector keys = m.fieldnames (); for (octave_idx_type i = 0; i < nf; i++) { @@ -1591,7 +998,7 @@ hdf5_callback_data dsub; herr_t retval2 = 0; - Octave_map m (dim_vector (1, 1)); + octave_map m (dim_vector (1, 1)); int current_item = 0; hsize_t num_obj = 0; #if HAVE_HDF5_18 @@ -1619,7 +1026,7 @@ return false; } - m.assign (dsub.name, tcell); + m.setfield (dsub.name, tcell); } @@ -1666,3 +1073,1124 @@ return retval; } + +octave_value +octave_struct::fast_elem_extract (octave_idx_type n) const +{ + if (n < map.numel ()) + return map.checkelem (n); + else + return octave_value (); +} + +bool +octave_struct::fast_elem_insert (octave_idx_type n, + const octave_value& x) +{ + bool retval = false; + + if (n < map.numel ()) + { + // To avoid copying the scalar struct, it just stores a pointer to + // itself. + const octave_scalar_map *sm_ptr; + void *here = reinterpret_cast<void *>(&sm_ptr); + return (x.get_rep().fast_elem_insert_self (here, btyp_struct) + && map.fast_elem_insert (n, *sm_ptr)); + } + + return retval; +} +DEFINE_OCTAVE_ALLOCATOR(octave_scalar_struct); + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_scalar_struct, "scalar struct", "struct"); + +octave_value +octave_scalar_struct::dotref (const octave_value_list& idx, bool auto_add) +{ + assert (idx.length () == 1); + + std::string nm = idx(0).string_value (); + + octave_value retval = map.getfield (nm); + + if (! auto_add && retval.is_undefined ()) + error ("structure has no member `%s'", nm.c_str ()); + + return retval; +} + +octave_value +octave_scalar_struct::subsref (const std::string& type, + const std::list<octave_value_list>& idx) +{ + octave_value retval; + + if (type[0] == '.') + { + int skip = 1; + + retval = dotref (idx.front ()); + + if (idx.size () > 1) + retval = retval.next_subsref (type, idx, skip); + } + else + retval = to_array ().subsref (type, idx); + + return retval; +} + +octave_value_list +octave_scalar_struct::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) +{ + octave_value_list retval; + + if (type[0] == '.') + { + int skip = 1; + + retval(0) = dotref (idx.front ()); + + if (idx.size () > 1) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + else + retval = to_array ().subsref (type, idx, nargout); + + return retval; +} + +octave_value +octave_scalar_struct::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + bool auto_add) +{ + octave_value retval; + + if (type[0] == '.') + { + int skip = 1; + + retval = dotref (idx.front (), auto_add); + + if (idx.size () > 1) + retval = retval.next_subsref (auto_add, type, idx, skip); + } + else + retval = to_array ().subsref (type, idx, auto_add); + + return retval; +} + +/* +%!test +%! x(1).a.a = 1; x(2).a.a = 2; +%! assert (size (x), [1, 2]); +%! assert (x(1).a.a, 1); +%! assert (x(2).a.a, 2); +*/ + +octave_value +octave_scalar_struct::numeric_conv (const octave_value& val, + const std::string& type) +{ + octave_value retval; + + if (type.length () > 0 && type[0] == '.' && ! val.is_map ()) + retval = octave_map (); + else + retval = val; + + return retval; +} + +octave_value +octave_scalar_struct::subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs) +{ + octave_value retval; + + if (idx.front ().empty ()) + { + error ("missing index in indexed assignment"); + return retval; + } + + if (type[0] == '.') + { + int n = type.length (); + + octave_value t_rhs = rhs; + + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (n > 1) + { + std::list<octave_value_list> next_idx (idx); + + next_idx.erase (next_idx.begin ()); + + std::string next_type = type.substr (1); + + octave_value tmp; + octave_map::iterator pkey = map.seek (key); + if (pkey != map.end ()) + { + map.contents (pkey).make_unique (); + tmp = map.contents (pkey); + } + + if (! error_state) + { + if (! tmp.is_defined () || tmp.is_zero_by_zero ()) + { + tmp = octave_value::empty_conv (next_type, rhs); + tmp.make_unique (); // probably a no-op. + } + else + // optimization: ignore the copy still stored inside our map. + tmp.make_unique (1); + + if (! error_state) + t_rhs = tmp.subsasgn (next_type, next_idx, rhs); + } + } + + if (! error_state) + map.setfield (key, t_rhs.storable_value ()); + else + gripe_failed_assignment (); + + count++; + retval = this; + } + else + { + // Forward this case to octave_struct. + octave_value tmp (new octave_struct (octave_map (map))); + retval = tmp.subsasgn (type, idx, rhs); + } + + return retval; +} + +octave_value +octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok) +{ + // octave_map handles indexing itself. + return octave_map (map).index (idx, resize_ok); +} + +size_t +octave_scalar_struct::byte_size (void) const +{ + // Neglect the size of the fieldnames. + + size_t retval = 0; + + for (octave_map::const_iterator p = map.begin (); p != map.end (); p++) + { + std::string key = map.key (p); + + octave_value val = octave_value (map.contents (p)); + + retval += val.byte_size (); + } + + return retval; +} + +void +octave_scalar_struct::print (std::ostream& os, bool) const +{ + print_raw (os); +} + +void +octave_scalar_struct::print_raw (std::ostream& os, bool) const +{ + unwind_protect frame; + + frame.protect_var (Vstruct_levels_to_print); + + if (Vstruct_levels_to_print >= 0) + { + bool print_keys_only = Vstruct_levels_to_print-- == 0; + + indent (os); + os << "{"; + newline (os); + + increment_indent_level (); + + octave_idx_type n = 1; + + if (n != 1 || print_keys_only) + { + indent (os); + dim_vector dv = dims (); + os << dv.str () << " struct array containing the fields:"; + newline (os); + newline (os); + + increment_indent_level (); + } + + string_vector key_list = map.fieldnames (); + + for (octave_idx_type i = 0; i < key_list.length (); i++) + { + std::string key = key_list[i]; + + Cell val = map.contents (key); + + octave_value tmp = (n == 1) ? val(0) : octave_value (val, true); + + if (n != 1 || print_keys_only) + { + indent (os); + os << key; + if (n == 1) + { + dim_vector dv = tmp.dims (); + os << ": " << dv.str () << " " << tmp.type_name (); + } + newline (os); + } + else + tmp.print_with_name (os, key); + } + + if (n != 1 || print_keys_only) + decrement_indent_level (); + + decrement_indent_level (); + + indent (os); + os << "}"; + newline (os); + } + else + { + indent (os); + os << "<structure>"; + newline (os); + } +} + +bool +octave_scalar_struct::print_name_tag (std::ostream& os, const std::string& name) const +{ + bool retval = false; + + indent (os); + + if (Vstruct_levels_to_print < 0) + os << name << " = "; + else + { + os << name << " ="; + newline (os); + retval = true; + } + + return retval; +} + +bool +octave_scalar_struct::save_ascii (std::ostream& os) +{ + octave_map m = map_value (); + + octave_idx_type nf = m.nfields (); + + const dim_vector dv = dims (); + + os << "# ndims: " << dv.length () << "\n"; + + for (int i = 0; i < dv.length (); i++) + os << " " << dv (i); + os << "\n"; + + os << "# length: " << nf << "\n"; + + // Iterating over the list of keys will preserve the order of the + // fields. + string_vector keys = m.fieldnames (); + + for (octave_idx_type i = 0; i < nf; i++) + { + std::string key = keys(i); + + octave_value val = map.contents (key); + + bool b = save_ascii_data (os, val, key, false, 0); + + if (! b) + return os; + } + + return true; +} + +bool +octave_scalar_struct::load_ascii (std::istream& is) +{ + bool success = true; + octave_idx_type len = 0; + + if (extract_keyword (is, "length", len) && len >= 0) + { + if (len > 0) + { + octave_scalar_map m; + + for (octave_idx_type j = 0; j < len; j++) + { + octave_value t2; + bool dummy; + + // recurse to read cell elements + std::string nm + = read_ascii_data (is, std::string (), dummy, t2, j); + + if (!is) + break; + + if (error_state) + { + error ("load: internal error loading struct elements"); + return false; + } + + m.setfield (nm, t2); + } + + if (is) + map = m; + else + { + error ("load: failed to load structure"); + success = false; + } + } + else if (len == 0) + map = octave_scalar_map (); + else + panic_impossible (); + } + else { + error ("load: failed to extract number of elements in structure"); + success = false; + } + + return success; +} + +bool +octave_scalar_struct::save_binary (std::ostream& os, bool& save_as_floats) +{ + octave_map m = map_value (); + + octave_idx_type nf = m.nfields (); + + int32_t len = nf; + os.write (reinterpret_cast<char *> (&len), 4); + + // Iterating over the list of keys will preserve the order of the + // fields. + string_vector keys = m.fieldnames (); + + for (octave_idx_type i = 0; i < nf; i++) + { + std::string key = keys(i); + + octave_value val = map.contents (key); + + bool b = save_binary_data (os, val, key, "", 0, save_as_floats); + + if (! b) + return os; + } + + return true; +} + +bool +octave_scalar_struct::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + bool success = true; + int32_t len; + if (! is.read (reinterpret_cast<char *> (&len), 4)) + return false; + if (swap) + swap_bytes<4> (&len); + + dim_vector dv (1, 1); + + if (len > 0) + { + octave_scalar_map m; + + for (octave_idx_type j = 0; j < len; j++) + { + octave_value t2; + bool dummy; + std::string doc; + + // recurse to read cell elements + std::string nm = read_binary_data (is, swap, fmt, std::string (), + dummy, t2, doc); + + if (!is) + break; + + if (error_state) + { + error ("load: internal error loading struct elements"); + return false; + } + + m.setfield (nm, t2); + } + + if (is) + map = m; + else + { + error ("load: failed to load structure"); + success = false; + } + } + else if (len == 0) + map = octave_scalar_map (); + else + success = false; + + return success; +} + +#if defined (HAVE_HDF5) + +bool +octave_scalar_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) +{ + hid_t data_hid = -1; + +#if HAVE_HDF5_18 + data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); +#else + data_hid = H5Gcreate (loc_id, name, 0); +#endif + if (data_hid < 0) return false; + + // recursively add each element of the structure to this group + octave_scalar_map m = scalar_map_value (); + + octave_idx_type nf = m.nfields (); + + // Iterating over the list of keys will preserve the order of the + // fields. + string_vector keys = m.fieldnames (); + + for (octave_idx_type i = 0; i < nf; i++) + { + std::string key = keys(i); + + octave_value val = map.contents (key); + + bool retval2 = add_hdf5_data (data_hid, val, key, "", false, + save_as_floats); + + if (! retval2) + break; + } + + H5Gclose (data_hid); + + return true; +} + +bool +octave_scalar_struct::load_hdf5 (hid_t loc_id, const char *name) +{ + bool retval = false; + + hdf5_callback_data dsub; + + herr_t retval2 = 0; + octave_scalar_map m; + int current_item = 0; + hsize_t num_obj = 0; +#if HAVE_HDF5_18 + hid_t group_id = H5Gopen (loc_id, name, H5P_DEFAULT); +#else + hid_t group_id = H5Gopen (loc_id, name); +#endif + H5Gget_num_objs (group_id, &num_obj); + H5Gclose (group_id); + + // FIXME -- fields appear to be sorted alphabetically on loading. + // Why is that happening? + + while (current_item < static_cast<int> (num_obj) + && (retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub)) > 0) + { + octave_value t2 = dsub.tc; + + if (error_state) + { + error ("load: internal error loading struct elements"); + return false; + } + + m.setfield (dsub.name, t2); + + } + + if (retval2 >= 0) + { + map = m; + retval = true; + } + + return retval; +} + +#endif + +mxArray * +octave_scalar_struct::as_mxArray (void) const +{ + int nf = nfields (); + string_vector kv = map_keys (); + + OCTAVE_LOCAL_BUFFER (const char *, f, nf); + + for (int i = 0; i < nf; i++) + f[i] = kv[i].c_str (); + + mxArray *retval = new mxArray (dims (), nf, f); + + mxArray **elts = static_cast<mxArray **> (retval->get_data ()); + + mwSize nel = numel (); + + mwSize ntot = nf * nel; + + for (int i = 0; i < nf; i++) + { + Cell c = map.contents (kv[i]); + + const octave_value *p = c.data (); + + mwIndex k = 0; + for (mwIndex j = i; j < ntot; j += nf) + elts[j] = new mxArray (p[k++]); + } + + return retval; +} + + +octave_value +octave_scalar_struct::to_array (void) +{ + return new octave_struct (octave_map (map)); +} + +bool +octave_scalar_struct::fast_elem_insert_self (void *where, builtin_type_t btyp) const +{ + + if (btyp == btyp_struct) + { + *(reinterpret_cast<const octave_scalar_map **>(where)) = ↦ + return true; + } + else + return false; +} +/* +%!shared x +%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3; +%!assert(struct('a',1,'b',3),x(1)) +%!assert(isempty(x([]))) +%!assert(isempty(struct('a',{},'b',{}))) +%!assert(struct('a',{1,2},'b',{3,3}),x) +%!assert(struct('a',{1,2},'b',3),x) +%!assert(struct('a',{1,2},'b',{3}),x) +%!assert(struct('b',3,'a',{1,2}),x) +%!assert(struct('b',{3},'a',{1,2}),x) +%!test x=struct([]); +%!assert(size(x),[0,0]); +%!assert(isstruct(x)); +%!assert(isempty(fieldnames(x))); +%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4") +%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs"); +%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs"); +*/ + +DEFUN (struct, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\ +\n\ +Create a structure and initialize its value.\n\ +\n\ +If the values are cell arrays, create a structure array and initialize\n\ +its values. The dimensions of each cell array of values must match.\n\ +Singleton cells and non-cell values are repeated so that they fill\n\ +the entire array. If the cells are empty, create an empty structure\n\ +array with the specified field names.\n\ +\n\ +If the argument is an object, return the underlying struct.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + // struct ([]) returns an empty struct. + + // struct (empty_matrix) returns an empty struct with the same + // dimensions as the empty matrix. + + // Note that struct () creates a 1x1 struct with no fields for + // compatibility with Matlab. + + if (nargin == 1 && args(0).is_map ()) + return args(0); + + if (nargin == 1 && args(0).is_object ()) + { + retval = args(0).map_value (); + + return retval; + } + + if ((nargin == 1 || nargin == 2) + && args(0).is_empty () && args(0).is_real_matrix ()) + { + Cell fields; + + if (nargin == 2) + { + if (args(1).is_cellstr ()) + retval = octave_map (args(0).dims (), args(1).cellstr_value ()); + else + error ("struct: expecting cell array of field names as second argument"); + } + else + retval = octave_map (args(0).dims ()); + + return retval; + } + + // Check for "field", VALUE pairs. + + for (int i = 0; i < nargin; i += 2) + { + if (! args(i).is_string () || i + 1 >= nargin) + { + error ("struct expects alternating \"field\", VALUE pairs"); + return retval; + } + } + + // Check that the dimensions of the values correspond. + + dim_vector dims (1, 1); + + int first_dimensioned_value = 0; + + for (int i = 1; i < nargin; i += 2) + { + if (args(i).is_cell ()) + { + dim_vector argdims (args(i).dims ()); + + if (! scalar (argdims)) + { + if (! first_dimensioned_value) + { + dims = argdims; + first_dimensioned_value = i + 1; + } + else if (dims != argdims) + { + error ("struct: dimensions of parameter %d do not match those of parameter %d", + first_dimensioned_value, i+1); + return retval; + } + } + } + } + + // Create the return value. + + octave_map map (dims); + + for (int i = 0; i < nargin; i+= 2) + { + // Get key. + + std::string key (args(i).string_value ()); + + if (error_state) + return retval; + + if (! valid_identifier (key)) + { + error ("struct: invalid structure field name `%s'", key.c_str ()); + return retval; + } + + // Value may be v, { v }, or { v1, v2, ... } + // In the first two cases, we need to create a cell array of + // the appropriate dimensions filled with v. In the last case, + // the cell array has already been determined to be of the + // correct dimensions. + + if (args(i+1).is_cell ()) + { + const Cell c (args(i+1).cell_value ()); + + if (error_state) + return retval; + + if (scalar (c.dims ())) + map.setfield (key, Cell (dims, c(0))); + else + map.setfield (key, c); + } + else + map.setfield (key, Cell (dims, args(i+1))); + + if (error_state) + return retval; + } + + return octave_value (map); +} + +DEFUN (isstruct, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\ +Return 1 if the value of the expression @var{expr} is a structure\n\ +(or a structure array).\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + retval = args(0).is_map (); + else + print_usage (); + + return retval; +} + +DEFUN (fieldnames, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\ +Return a cell array of strings naming the elements of the structure\n\ +@var{struct}. It is an error to call @code{fieldnames} with an\n\ +argument that is not a structure.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1) + { + octave_value arg = args(0); + + if (arg.is_map () || arg.is_object ()) + { + octave_map m = arg.map_value (); + + string_vector keys = m.fieldnames (); + + if (keys.length () == 0) + retval = Cell (0, 1); + else + retval = Cell (keys); + } + else + gripe_wrong_type_arg ("fieldnames", args(0)); + } + else + print_usage (); + + return retval; +} + +/* +%!# test preservation of fieldname order +%!test +%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; +%! assert(fieldnames(x), {"d"; "a"; "b"; "c"}); +*/ + +DEFUN (isfield, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\ +Return true if the expression @var{expr} is a structure and it\n\ +includes an element named @var{name}. If @var{name} is a cell\n\ +array, a logical array of equal dimension is returned.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 2) + { + retval = false; + + if (args(0).is_map ()) + { + octave_map m = args(0).map_value (); + + // FIXME -- should this work for all types that can do + // structure reference operations? + + if (args(1).is_string ()) + { + std::string key = args(1).string_value (); + + retval = m.isfield (key); + } + else if (args(1).is_cell ()) + { + Cell c = args(1).cell_value (); + boolNDArray bm (c.dims ()); + octave_idx_type n = bm.numel (); + + for (octave_idx_type i = 0; i < n; i++) + { + if (c(i).is_string ()) + { + std::string key = c(i).string_value (); + + bm(i) = m.isfield (key); + } + else + bm(i) = false; + } + + retval = bm; + } + } + } + else + print_usage (); + + return retval; +} + +DEFUN (nfields, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} nfields (@var{s})\n\ +Return the number of fields of the structure @var{s}.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1 && args(0).is_map ()) + { + retval = static_cast<double> (args(0).nfields ()); + } + else + print_usage (); + + return retval; +} + +/* +%!# test isfield +%!test +%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; +%! assert (isfield (x, "b")); +%!assert( isfield( struct("a", "1"), "a")); +%!assert( isfield( {1}, "c"), logical (0)); +%!assert( isfield( struct("a", "1"), 10), logical (0)); +%!assert( isfield( struct("a", "b"), "a "), logical (0)); + +*/ + +DEFUN (cell2struct, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\ +Convert @var{cell} to a structure. The number of fields in @var{fields}\n\ +must match the number of elements in @var{cell} along dimension @var{dim},\n\ +that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\ +\n\ +@example\n\ +@group\n\ +A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\ + 185, 170, 168@},\n\ + @{'Name','Height'@}, 1);\n\ +A(1)\n\ + @result{} ans =\n\ + @{\n\ + Name = Peter\n\ + Height = 185\n\ + @}\n\ +\n\ +@end group\n\ +@end example\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 3) + { + if (! args(0).is_cell ()) + error ("cell2struct: first argument must be a cell"); + else if (! (args(1).is_cellstr () || args(1).is_char_matrix ())) + error ("cell2struct: second argument must be a cell array of strings or a character matrix"); + else if (! args(2).is_real_scalar ()) + error ("cell2struct: third argument must be a real scalar"); + else + { + const Cell vals = args(0).cell_value (); + const Array<std::string> fields = args(1).cellstr_value (); + int dim = args(2).int_value () - 1; + octave_idx_type ext = 0; + + if (dim < 0) + error ("cell2struct: dim must be a valid dimension"); + else + { + ext = vals.ndims () > dim ? vals.dims ()(dim) : 1; + if (ext != fields.numel ()) + error ("cell2struct: number of fields doesn't match dimension"); + } + + + if (! error_state) + { + int nd = std::max (dim+1, vals.ndims ()); + // result dimensions. + dim_vector rdv = vals.dims ().redim (nd); + + assert (ext == rdv(dim)); + if (nd == 2) + { + rdv(0) = rdv(1-dim); + rdv(1) = 1; + } + else + { + for (int i = dim + 1; i < nd; i++) + rdv(i-1) = rdv(i); + + rdv.resize (nd-1); + } + + octave_map map (rdv); + Array<idx_vector> ia (nd, 1, idx_vector::colon); + + for (octave_idx_type i = 0; i < ext; i++) + { + ia(dim) = i; + map.setfield (fields(i), vals.index (ia).reshape (rdv)); + } + + retval = map; + } + } + } + else + print_usage (); + + return retval; +} + +/* +%!# test cell2struct versus struct2cell +%!test +%! keys = cellstr (char (floor (rand (100,10)*24+65)))'; +%! vals = mat2cell(rand (100,1), ones (100,1), 1)'; +%! s = struct ([keys; vals]{:}); +%! t = cell2struct (vals, keys, 2); +%! assert (s, t); +%! assert (struct2cell (s), vals'); +%! assert (fieldnames (s), keys'); +*/ + + +// So we can call Fcellstr directly. +extern octave_value_list Fcellstr (const octave_value_list& args, int); + +DEFUN (rmfield, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\ +Return a copy of the structure (array) @var{s} with the field @var{f} removed.\n\ +If @var{f} is a cell array of strings or a character array, remove the\n\ +named fields.\n\ +@seealso{cellstr, iscellstr, setfield}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 2) + { + octave_map m = args(0).map_value (); + + octave_value_list fval = Fcellstr (args(1), 1); + + if (! error_state) + { + Cell fcell = fval(0).cell_value (); + + for (int i = 0; i < fcell.numel (); i++) + { + std::string key = fcell(i).string_value (); + + if (m.isfield (key)) + m.rmfield (key); + else + { + error ("rmfield: structure does not contain field %s", + key.c_str ()); + + break; + } + } + + if (! error_state) + retval = m; + } + } + else + print_usage (); + + return retval; +} + +/* +%!# test rmfield +%!test +%! x(3).d=1; x(2).a=2; x(1).b=3; x(2).c=3; x(6).f="abc123"; +%! y = rmfield (x, {"a", "f"}); +%! assert (fieldnames (y), {"d"; "b"; "c"}); +%! assert (size (y), [1, 6]); +*/ +
--- a/src/ov-struct.h +++ b/src/ov-struct.h @@ -52,6 +52,9 @@ octave_struct (void) : octave_base_value () { } + octave_struct (const octave_map& m) + : octave_base_value (), map (m) { } + octave_struct (const Octave_map& m) : octave_base_value (), map (m) { } @@ -63,6 +66,8 @@ octave_base_value *clone (void) const { return new octave_struct (*this); } octave_base_value *empty_clone (void) const { return new octave_struct (); } + octave_base_value *try_narrowing_conversion (void); + Cell dotref (const octave_value_list& idx, bool auto_add = false); octave_value subsref (const std::string& type, @@ -102,8 +107,7 @@ // of elements is numel () * nfields (). octave_idx_type numel (void) const { - dim_vector dv = dims (); - return dv.numel (); + return map.numel (); } octave_idx_type nfields (void) const { return map.nfields (); } @@ -111,8 +115,8 @@ octave_value reshape (const dim_vector& new_dims) const { return map.reshape (new_dims); } - octave_value resize (const dim_vector& dv, bool = false) const - { Octave_map tmap = map; tmap.resize (dv); return tmap; } + octave_value resize (const dim_vector& dv, bool fill = false) const + { octave_map tmap = map; tmap.resize (dv, fill); return tmap; } bool is_defined (void) const { return true; } @@ -122,9 +126,9 @@ builtin_type_t builtin_type (void) const { return btyp_struct; } - Octave_map map_value (void) const { return map; } + octave_map map_value (void) const { return map; } - string_vector map_keys (void) const { return map.keys (); } + string_vector map_keys (void) const { return map.fieldnames (); } void print (std::ostream& os, bool pr_as_read_syntax = false) const; @@ -149,10 +153,16 @@ mxArray *as_mxArray (void) const; + octave_value + fast_elem_extract (octave_idx_type n) const; + + bool + fast_elem_insert (octave_idx_type n, const octave_value& x); + protected: // The associative array used to manage the structure data. - Octave_map map; + octave_map map; private: @@ -161,4 +171,123 @@ DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA }; +class +octave_scalar_struct : public octave_base_value +{ +public: + + octave_scalar_struct (void) + : octave_base_value () { } + + octave_scalar_struct (const octave_scalar_map& m) + : octave_base_value (), map (m) { } + + octave_scalar_struct (const octave_scalar_struct& s) + : octave_base_value (), map (s.map) { } + + ~octave_scalar_struct (void) { } + + octave_base_value *clone (void) const { return new octave_scalar_struct (*this); } + octave_base_value *empty_clone (void) const { return new octave_scalar_struct (); } + + octave_value dotref (const octave_value_list& idx, bool auto_add = false); + + octave_value subsref (const std::string& type, + const std::list<octave_value_list>& idx); + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, int); + + + octave_value subsref (const std::string& type, + const std::list<octave_value_list>& idx, + bool auto_add); + + static octave_value numeric_conv (const octave_value& val, + const std::string& type); + + octave_value subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs); + + octave_value squeeze (void) const { return map; } + + octave_value permute (const Array<int>& vec, bool inv = false) const + { return octave_map (map).permute (vec, inv); } + + octave_value do_index_op (const octave_value_list& idx, + bool resize_ok = false); + + dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; } + + size_t byte_size (void) const; + + // This is the number of elements in each field. The total number + // of elements is numel () * nfields (). + octave_idx_type numel (void) const + { + return 1; + } + + octave_idx_type nfields (void) const { return map.nfields (); } + + octave_value reshape (const dim_vector& new_dims) const + { return octave_map (map).reshape (new_dims); } + + octave_value resize (const dim_vector& dv, bool fill = false) const + { octave_map tmap = map; tmap.resize (dv, fill); return tmap; } + + bool is_defined (void) const { return true; } + + bool is_constant (void) const { return true; } + + bool is_map (void) const { return true; } + + builtin_type_t builtin_type (void) const { return btyp_struct; } + + octave_map map_value (void) const { return map; } + + octave_scalar_map scalar_map_value (void) const { return map; } + + string_vector map_keys (void) const { return map.fieldnames (); } + + void print (std::ostream& os, bool pr_as_read_syntax = false) const; + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + + bool print_name_tag (std::ostream& os, const std::string& name) const; + + bool save_ascii (std::ostream& os); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name); #endif + + mxArray *as_mxArray (void) const; + + bool fast_elem_insert_self (void *where, builtin_type_t btyp) const; + +protected: + + // The associative array used to manage the structure data. + octave_scalar_map map; + +private: + + octave_value to_array (void); + + DECLARE_OCTAVE_ALLOCATOR + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA +}; + +#endif
--- a/src/ov.cc +++ b/src/ov.cc @@ -1116,9 +1116,21 @@ maybe_mutate (); } +octave_value::octave_value (const octave_map& m) + : rep (new octave_struct (m)) +{ + maybe_mutate (); +} + +octave_value::octave_value (const octave_scalar_map& m) + : rep (new octave_scalar_struct (m)) +{ +} + octave_value::octave_value (const Octave_map& m) : rep (new octave_struct (m)) { + maybe_mutate (); } octave_value::octave_value (const Octave_map& m, const std::string& id) @@ -1431,12 +1443,18 @@ #endif } -Octave_map +octave_map octave_value::map_value (void) const { return rep->map_value (); } +octave_scalar_map +octave_value::scalar_map_value (void) const +{ + return rep->scalar_map_value (); +} + octave_function * octave_value::function_value (bool silent) const { @@ -2569,7 +2587,7 @@ case '(': { if (type.length () > 1 && type[1] == '.') - retval = Octave_map (); + retval = octave_map (); else retval = octave_value (rhs.empty_clone ()); } @@ -2580,7 +2598,7 @@ break; case '.': - retval = Octave_map (); + retval = octave_scalar_map (); break; default: @@ -2629,6 +2647,7 @@ octave_sparse_matrix::register_type (); octave_sparse_complex_matrix::register_type (); octave_struct::register_type (); + octave_scalar_struct::register_type (); octave_class::register_type (); octave_cs_list::register_type (); octave_magic_colon::register_type ();
--- a/src/ov.h +++ b/src/ov.h @@ -45,6 +45,8 @@ #include "oct-sort.h" class Cell; +class octave_map; +class octave_scalar_map; class Octave_map; class octave_stream; class octave_function; @@ -275,6 +277,8 @@ octave_value (const idx_vector& idx, bool lazy = true); octave_value (double base, double limit, double inc); octave_value (const Range& r); + octave_value (const octave_map& m); + octave_value (const octave_scalar_map& m); octave_value (const Octave_map& m); octave_value (const Octave_map& m, const std::string& id); octave_value (const octave_value_list& m, bool = false); @@ -840,7 +844,9 @@ Range range_value (void) const { return rep->range_value (); } - Octave_map map_value (void) const; + octave_map map_value (void) const; + + octave_scalar_map scalar_map_value (void) const; string_vector map_keys (void) const { return rep->map_keys (); }
--- a/src/pt-mat.cc +++ b/src/pt-mat.cc @@ -70,14 +70,14 @@ all_sq_str (false), all_dq_str (false), some_str (false), all_real (false), all_cmplx (false), all_mt (true), any_sparse (false), any_class (false), - class_nm (), ok (false) + all_1x1 (false), class_nm (), ok (false) { } tm_row_const_rep (const tree_argument_list& row) : count (1), dv (0, 0), all_str (false), all_sq_str (false), some_str (false), all_real (false), all_cmplx (false), all_mt (true), any_sparse (false), any_class (false), - class_nm (), ok (false) + all_1x1 (! row.empty ()), class_nm (), ok (false) { init (row); } ~tm_row_const_rep (void) { } @@ -95,6 +95,7 @@ bool all_mt; bool any_sparse; bool any_class; + bool all_1x1; std::string class_nm; @@ -171,6 +172,7 @@ bool all_empty_p (void) const { return rep->all_mt; } bool any_sparse_p (void) const { return rep->any_sparse; } bool any_class_p (void) const { return rep->any_class; } + bool all_1x1_p (void) const { return rep->all_1x1; } std::string class_name (void) const { return rep->class_nm; } @@ -249,6 +251,10 @@ retval = c2; else if (c1_is_logical && c2_is_logical) retval = c1; + else if (c1 == "struct" && c2 == c1) + retval = c1; + else if (c1 == "cell" && c2 == c1) + retval = c1; } return retval; @@ -322,6 +328,8 @@ if (!any_class && val.is_object ()) any_class = true; + all_1x1 = all_1x1 && val.numel () == 1; + return true; } @@ -416,6 +424,7 @@ bool all_empty_p (void) const { return all_mt; } bool any_sparse_p (void) const { return any_sparse; } bool any_class_p (void) const { return any_class; } + bool all_1x1_p (void) const { return all_1x1; } std::string class_name (void) const { return class_nm; } @@ -434,6 +443,7 @@ bool all_mt; bool any_sparse; bool any_class; + bool all_1x1; std::string class_nm; @@ -458,6 +468,7 @@ all_cmplx = true; any_sparse = false; any_class = false; + all_1x1 = ! empty (); bool first_elem = true; @@ -503,6 +514,8 @@ if (!any_class && tmp.any_class_p ()) any_class = true; + all_1x1 = all_1x1 && tmp.all_1x1_p (); + append (tmp); } else @@ -677,6 +690,7 @@ { // If possible, forward the operation to liboctave. // Single row. + // FIXME: optimize all scalars case. tm_row_const& row = tmp.front (); octave_idx_type ncols = row.length (), i = 0; OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols); @@ -748,6 +762,49 @@ result = Sparse<T>::cat (0, nrows, sparse_row_list); } +template<class MAP> +static void +single_type_concat (octave_map& result, + const dim_vector& dv, + tm_const& tmp) +{ + if (dv.any_zero ()) + { + result = octave_map (dv); + return; + } + + octave_idx_type nrows = tmp.length (), j = 0; + OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows); + for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) + { + tm_row_const row = *p; + octave_idx_type ncols = row.length (), i = 0; + OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols); + + for (tm_row_const::iterator q = row.begin (); + q != row.end () && ! error_state; + q++) + { + octave_quit (); + + // Use 0x0 in place of all empty arrays to allow looser rules. + // If MAP is octave_scalar_map, the condition is vacuously true. + if (! q->is_empty ()) + map_list[i] = octave_value_extract<MAP> (*q); + i++; + } + + octave_map mtmp = octave_map::cat (1, ncols, map_list); + // Use 0x0 in place of all empty arrays to allow looser rules. + if (! mtmp.is_empty ()) + map_row_list[j] = mtmp; + j++; + } + + result = octave_map::cat (0, nrows, map_row_list); +} + template<class TYPE> static octave_value do_single_type_concat (const dim_vector& dv, @@ -760,6 +817,21 @@ return result; } +template<> +octave_value +do_single_type_concat<octave_map> (const dim_vector& dv, + tm_const& tmp) +{ + octave_map result; + + if (tmp.all_1x1_p ()) + single_type_concat<octave_scalar_map> (result, dv, tmp); + else + single_type_concat<octave_map> (result, dv, tmp); + + return result; +} + template<class TYPE, class OV_TYPE> static octave_value do_single_type_concat_no_mutate (const dim_vector& dv, @@ -929,6 +1001,10 @@ retval = do_single_type_concat<uint32NDArray> (dv, tmp); else if (result_type == "uint64") retval = do_single_type_concat<uint64NDArray> (dv, tmp); + else if (result_type == "cell") + retval = do_single_type_concat<Cell> (dv, tmp); + else if (result_type == "struct") + retval = do_single_type_concat<octave_map> (dv, tmp); else { // The line below might seem crazy, since we take a copy of
--- a/src/syscalls.cc +++ b/src/syscalls.cc @@ -57,10 +57,10 @@ #include "variables.h" #include "input.h" -static Octave_map +static octave_scalar_map mk_stat_map (const base_file_stat& fs) { - Octave_map m; + octave_scalar_map m; m.assign ("dev", static_cast<double> (fs.dev ())); m.assign ("ino", fs.ino ()); @@ -1202,7 +1202,7 @@ { octave_uname sysinfo; - Octave_map m; + octave_scalar_map m; m.assign ("sysname", sysinfo.sysname ()); m.assign ("nodename", sysinfo.nodename ());
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -234,12 +234,22 @@ return retval; } -Octave_map +// Use static fields for the best efficiency. +// NOTE: C++0x will allow these two to be merged into one. +static const char *bt_fieldnames[] = { "file", "name", "line", + "column", "scope", "context", 0 }; +static const octave_fields bt_fields (bt_fieldnames); + +octave_map +octave_call_stack::empty_backtrace (void) +{ + return octave_map (dim_vector (0, 1), bt_fields); +} + +octave_map octave_call_stack::do_backtrace (size_t nskip, octave_idx_type& curr_user_frame) const { - Octave_map retval; - size_t user_code_frames = do_num_user_code_frames (curr_user_frame); size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0; @@ -247,21 +257,14 @@ // Our list is reversed. curr_user_frame = nframes - curr_user_frame - 1; - Cell keys (6, 1); + octave_map retval (dim_vector (nframes, 1), bt_fields); - keys(0) = "file"; - keys(1) = "name"; - keys(2) = "line"; - keys(3) = "column"; - keys(4) = "scope"; - keys(5) = "context"; - - Cell file (nframes, 1); - Cell name (nframes, 1); - Cell line (nframes, 1); - Cell column (nframes, 1); - Cell scope (nframes, 1); - Cell context (nframes, 1); + Cell& file = retval.contents (0); + Cell& name = retval.contents (1); + Cell& line = retval.contents (2); + Cell& column = retval.contents (3); + Cell& scope = retval.contents (4); + Cell& context = retval.contents (5); if (nframes > 0) { @@ -306,13 +309,6 @@ } } } - - retval.assign ("file", file); - retval.assign ("name", name); - retval.assign ("line", line); - retval.assign ("column", column); - retval.assign ("scope", scope); - retval.assign ("context", context); } return retval;
--- a/src/toplev.h +++ b/src/toplev.h @@ -266,12 +266,14 @@ instance->do_goto_base_frame (); } - static Octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame) + static octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame) { return instance_ok () - ? instance->do_backtrace (nskip, curr_user_frame) : Octave_map (); + ? instance->do_backtrace (nskip, curr_user_frame) : octave_map (); } + static octave_map empty_backtrace (void); + static void pop (void) { if (instance_ok ()) @@ -389,7 +391,7 @@ } } - Octave_map do_backtrace (size_t nskip, + octave_map do_backtrace (size_t nskip, octave_idx_type& curr_user_frame) const; bool do_goto_frame (size_t n, bool verbose);