# HG changeset patch # User Jaroslav Hajek # Date 1266045441 -3600 # Node ID 97b4bd6f09255e1ab6879200eafd7c7214e51d7d # Parent 907d470e261b9d383c91b63e950ecbecff6c9f35 partially rewrite function handles diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2010-02-13 Jaroslav Hajek + + * load-path.cc (load_path::do_any_class_method): Rename to + do_overloads. Return a list of classes. + * load-path.h (load_path::any_class_method): Likewise. + * symtab.cc (get_dispatch_type): Rewrite. + * symtab.h (get_dispatch_type): Update decl. + * ov-fcn-handle.h (octave_fcn_handle): Partially rewrite. + (octave_fcn_handle::builtin_overloads, octave_fcn_handle::overloads, + octave_fcn_handle::has_overloads): New members. + * ov-fcn-handle.cc (octave_fcn_handle::do_multi_index_op): Rewrite. + (make_fcn_handle): Partially rewrite. + 2010-02-11 John W. Eaton * DLD-FUNCTIONS/config-module.awk, genprops.awk, graphics.h.in, diff --git a/src/load-path.cc b/src/load-path.cc --- a/src/load-path.cc +++ b/src/load-path.cc @@ -1075,10 +1075,10 @@ return retval; } -bool -load_path::do_any_class_method (const std::string& meth) const +std::list +load_path::do_overloads (const std::string& meth) const { - bool retval = false; + std::list retval; // update (); @@ -1088,10 +1088,7 @@ const fcn_map_type& m = q->second; if (m.find (meth) != m.end ()) - { - retval = true; - break; - } + retval.push_back (q->first); } return retval; diff --git a/src/load-path.h b/src/load-path.h --- a/src/load-path.h +++ b/src/load-path.h @@ -108,10 +108,10 @@ ? instance->do_methods (class_name) : std::list (); } - static bool any_class_method (const std::string& meth) + static std::list overloads (const std::string& meth) { return instance_ok () - ? instance->do_any_class_method (meth) : false; + ? instance->do_overloads (meth) : std::list (); } static std::string find_fcn (const std::string& fcn, std::string& dir_name) @@ -479,7 +479,7 @@ std::list do_methods (const std::string& class_name) const; - bool do_any_class_method (const std::string& meth) const; + std::list do_overloads (const std::string& meth) const; std::string do_find_file (const std::string& file) const; diff --git a/src/ov-fcn-handle.cc b/src/ov-fcn-handle.cc --- a/src/ov-fcn-handle.cc +++ b/src/ov-fcn-handle.cc @@ -72,7 +72,7 @@ octave_fcn_handle::octave_fcn_handle (const octave_value& f, const std::string& n) - : fcn (f), nm (n) + : fcn (f), nm (n), has_overloads (false) { octave_user_function *uf = fcn.user_function_value (true); @@ -125,46 +125,39 @@ { octave_value_list retval; - if (fcn.is_defined ()) - out_of_date_check (fcn, std::string (), false); + out_of_date_check (fcn, std::string (), false); - if (disp.get () && ! args.empty ()) + if (has_overloads) { // Possibly overloaded function. - octave_value ovfcn = fcn; + octave_value ov_fcn; - // No need to compute built-in class dispatch if we don't have builtin class overloads. - bool builtin_class = ! disp->empty (); - // Get dynamic (class) dispatch type. - std::string dt = get_dispatch_type (args, builtin_class); + // Compute dispatch type. + builtin_type_t btyp; + std::string dispatch_type = get_dispatch_type (args, btyp); - if (! dt.empty ()) + // Retrieve overload. + if (btyp != btyp_unknown) { - str_ov_map::iterator pos = disp->find (dt); - if (pos != disp->end ()) + out_of_date_check (builtin_overloads[btyp], dispatch_type, false); + ov_fcn = builtin_overloads[btyp]; + } + else + { + str_ov_map::iterator it = overloads.find (dispatch_type); + if (it != overloads.end ()) { - out_of_date_check (pos->second, dt, false); - ovfcn = pos->second; - } - else if (! builtin_class) - { - octave_value method = symbol_table::find_method (nm, dt); - if (method.is_defined ()) - (*disp)[dt] = ovfcn = method; + out_of_date_check (it->second, dispatch_type, false); + ov_fcn = it->second; } } - if (ovfcn.is_defined ()) - retval = ovfcn.do_multi_index_op (nargout, args); - else if (fcn.is_undefined ()) - { - if (dt.empty ()) - dt = args(0).class_name (); - - error ("no %s method to handle class %s", nm.c_str (), dt.c_str ()); - } + if (ov_fcn.is_defined ()) + retval = ov_fcn.do_multi_index_op (nargout, args); + else if (fcn.is_defined ()) + retval = fcn.do_multi_index_op (nargout, args); else - error ("invalid function handle"); + error ("%s: no method for class %s", nm.c_str (), dispatch_type.c_str ()); } else { @@ -172,7 +165,7 @@ if (fcn.is_defined ()) retval = fcn.do_multi_index_op (nargout, args); else - error ("invalid function handle"); + error ("%s: no longer valid function handle", nm.c_str ()); } return retval; @@ -1463,49 +1456,57 @@ bool handle_ok = false; octave_value f = symbol_table::find_function (tnm, octave_value_list (), local_funcs); + octave_function *fptr = f.function_value (true); - if (f.is_undefined ()) + if (local_funcs && fptr + && (fptr->is_nested_function () || fptr->is_private_function () + || fptr->is_class_constructor ())) { - if (load_path::any_class_method (tnm)) - handle_ok = true; - else - { - load_path::update (); - if (load_path::any_class_method (tnm)) - handle_ok = true; - } + // Locally visible function. + retval = octave_value (new octave_fcn_handle (f, tnm)); } else - handle_ok = true; - - octave_function *fptr = f.is_defined () ? f.function_value () : 0; - + { + // Globally visible (or no match yet). Query overloads. + std::list classes = load_path::overloads (tnm); + bool any_match = fptr != 0 || classes.size () > 0; + if (! any_match) + { + // No match found, try updating load_path and query classes again. + load_path::update (); + classes = load_path::overloads (tnm); + any_match = classes.size () > 0; + } - if (handle_ok) - { - // If it's a subfunction, private function, or class constructor, - // we want no dispatch. - if (fptr && (fptr->is_nested_function () || fptr->is_private_function () - || fptr->is_class_constructor ())) - retval = octave_value (new octave_fcn_handle (f, tnm)); - else + if (any_match) { - typedef octave_fcn_handle::str_ov_map str_ov_map; - std::auto_ptr disp (new str_ov_map); - const string_vector cnames = get_builtin_classes (); - for (octave_idx_type i = 0; i < cnames.length (); i++) + octave_fcn_handle *fh = new octave_fcn_handle (f, tnm); + retval = fh; + + for (std::list::iterator iter = classes.begin (); + iter != classes.end (); iter++) { - std::string cnam = cnames(i); - octave_value method = symbol_table::find_method (tnm, cnam); - if (method.is_defined ()) - (*disp)[cnam] = method; - } + std::string class_name = *iter; + octave_value fmeth = symbol_table::find_method (tnm, class_name); - retval = octave_value (new octave_fcn_handle (f, tnm, disp.release ())); + bool is_builtin = false; + for (int i = 0; i < btyp_num_types; i++) + { + // FIXME: Too slow? Maybe binary lookup? + if (class_name == btyp_class_name[i]) + { + is_builtin = true; + fh->set_overload (static_cast (i), fmeth); + } + } + + if (! is_builtin) + fh->set_overload (class_name, fmeth); + } } + else + error ("@%s: no function and no method found", tnm.c_str ()); } - else - error ("error creating function handle \"@%s\"", nm.c_str ()); return retval; } diff --git a/src/ov-fcn-handle.h b/src/ov-fcn-handle.h --- a/src/ov-fcn-handle.h +++ b/src/ov-fcn-handle.h @@ -44,27 +44,26 @@ typedef std::map str_ov_map; - octave_fcn_handle (const octave_value& f, const std::string& n, - str_ov_map *sdisp) - : fcn (f), nm (n), disp (sdisp) { } - public: static const std::string anonymous; octave_fcn_handle (void) - : fcn (), nm () { } + : fcn (), nm (), has_overloads (false) { } octave_fcn_handle (const std::string& n) - : fcn (), nm (n) { } + : fcn (), nm (n), has_overloads (false) { } octave_fcn_handle (const octave_value& f, const std::string& n = anonymous); octave_fcn_handle (const octave_fcn_handle& fh) - : octave_base_value (fh), fcn (fh.fcn), nm (fh.nm) - { - if (fh.disp.get ()) - disp.reset (new str_ov_map (*fh.disp)); + : octave_base_value (fh), fcn (fh.fcn), nm (fh.nm), + has_overloads (fh.has_overloads) + { + for (int i = 0; i < btyp_num_types; i++) + builtin_overloads[i] = fh.builtin_overloads[i]; + + overloads = fh.overloads; } ~octave_fcn_handle (void) { } @@ -92,7 +91,7 @@ builtin_type_t builtin_type (void) const { return btyp_func_handle; } - bool is_overloaded (void) const { return disp.get () && ! disp->empty (); } + bool is_overloaded (void) const { return has_overloads; } dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; } @@ -108,6 +107,22 @@ std::string fcn_name (void) const { return nm; } + void set_overload (builtin_type_t btyp, const octave_value& ov_fcn) + { + if (btyp != btyp_unknown) + { + has_overloads = true; + builtin_overloads[btyp] = ov_fcn; + } + + } + + void set_overload (const std::string& dispatch_type, const octave_value& ov_fcn) + { + has_overloads = true; + overloads[dispatch_type] = ov_fcn; + } + bool save_ascii (std::ostream& os); bool load_ascii (std::istream& is); @@ -143,9 +158,14 @@ // The name of the handle, including the "@". std::string nm; - // A pointer to statical dispatch to standard classes. If null, we don't want - // to dispatch at all. - std::auto_ptr disp; + // Whether the function is overloaded at all. + bool has_overloads; + + // Overloads for builtin types. We use array to make lookup faster. + octave_value builtin_overloads[btyp_num_types]; + + // Overloads for other classes. + str_ov_map overloads; friend octave_value make_fcn_handle (const std::string &, bool); }; diff --git a/src/symtab.cc b/src/symtab.cc --- a/src/symtab.cc +++ b/src/symtab.cc @@ -477,7 +477,7 @@ std::string get_dispatch_type (const octave_value_list& args, - bool& builtin_class) + builtin_type_t& builtin_type) { static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table (); std::string dispatch_type; @@ -486,63 +486,49 @@ if (n > 0) { - // Find first object, if any. - - for (int i = 0; i < n; i++) + int i = 0; + builtin_type = args(0).builtin_type (); + if (builtin_type != btyp_unknown) { - octave_value arg = args(i); - - if (arg.is_object ()) + for (i = 1; i < n; i++) { - dispatch_type = arg.class_name (); - for (int j = i+1; j < n; j++) + builtin_type_t bti = args(i).builtin_type (); + if (bti != btyp_unknown) + builtin_type = sup_table[builtin_type][bti]; + else { - octave_value arg1 = args(j); - - if (arg1.is_object ()) - { - std::string cname = arg1.class_name (); - - // Only switch to type of ARG if it is marked superior - // to the current DISPATCH_TYPE. - if (! symbol_table::is_superiorto (dispatch_type, cname) - && symbol_table::is_superiorto (cname, dispatch_type)) - dispatch_type = cname; - } + builtin_type = btyp_unknown; + break; } - - builtin_class = false; - break; } } - // No object. + if (builtin_type == btyp_unknown) + { + // There's a non-builtin class in the argument list. + dispatch_type = args(i).class_name (); - if (builtin_class) - { - // Use the builtin_type mechanism to do this by one method call per - // element. + for (int j = i+1; j < n; j++) + { + octave_value arg = args(j); - int i = 0; - builtin_type_t btyp = args(0).builtin_type (); - if (btyp != btyp_unknown) - { - for (i = 1; i < n; i++) + if (arg.builtin_type () == btyp_unknown) { - builtin_type_t bti = args(i).builtin_type (); - if (bti == btyp_unknown) - break; - btyp = sup_table[btyp][bti]; + std::string cname = arg.class_name (); + + // Only switch to type of ARG if it is marked superior + // to the current DISPATCH_TYPE. + if (! symbol_table::is_superiorto (dispatch_type, cname) + && symbol_table::is_superiorto (cname, dispatch_type)) + dispatch_type = cname; } } - - // If there was an unknown type, we just take the class name of that value. - if (i == n) - dispatch_type = btyp_class_name[btyp]; - else - dispatch_type = args(i).class_name (); } + else + dispatch_type = btyp_class_name[builtin_type]; } + else + builtin_type = btyp_unknown; return dispatch_type; } @@ -550,8 +536,8 @@ std::string get_dispatch_type (const octave_value_list& args) { - bool builtin_class = true; - return get_dispatch_type (args, builtin_class); + builtin_type_t builtin_type; + return get_dispatch_type (args, builtin_type); } // Find the definition of NAME according to the following precedence diff --git a/src/symtab.h b/src/symtab.h --- a/src/symtab.h +++ b/src/symtab.h @@ -2373,6 +2373,6 @@ extern OCTINTERP_API std::string get_dispatch_type (const octave_value_list& args); extern OCTINTERP_API std::string -get_dispatch_type (const octave_value_list& args, bool& builtin_class); +get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type); #endif