octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Branching on builtin_type ()


From: John W. Eaton
Subject: Branching on builtin_type ()
Date: Mon, 5 Mar 2012 17:18:04 -0500

On  5-Mar-2012, Jordi Gutiérrez Hermoso wrote:

| While reading Jaroslav's code, I frequently come across constructs
| like this one:
| 
|           switch (argx.builtin_type ())
|             {
|             case btyp_double:
|               retval = argx.array_value ().nth_element (n, dim);
|               break;
|             case btyp_float:
|               retval = argx.float_array_value ().nth_element (n, dim);
|               break;
|             case btyp_complex:
|               retval = argx.complex_array_value ().nth_element (n, dim);
|               break;
|             case btyp_float_complex:
|               retval = argx.float_complex_array_value ().nth_element (n, dim);
|               break;
|     #define MAKE_INT_BRANCH(X) \
|             case btyp_ ## X: \
|               retval = argx.X ## _array_value ().nth_element (n, dim); \
|               break
| 
|             MAKE_INT_BRANCH (int8);
|             MAKE_INT_BRANCH (int16);
|             MAKE_INT_BRANCH (int32);
|             MAKE_INT_BRANCH (int64);
|             MAKE_INT_BRANCH (uint8);
|             MAKE_INT_BRANCH (uint16);
|             MAKE_INT_BRANCH (uint32);
|             MAKE_INT_BRANCH (uint64);
|     #undef MAKE_INT_BRANCH
|             default:
|               if (argx.is_cellstr ())
|                 retval = argx.cellstr_value ().nth_element (n, dim);
|               else
|                 gripe_wrong_type_arg ("nth_element", argx);
|             }
| 
| This is from data.cc:6415 @ rev ec660526ae50.
| 
| Can't this be improved? This manual polymorphism is error-prone and
| ugly to read. Isn't there an abstract array type that one can convert
| an octave_value into and then call virtual functions on this type?

I think the right thing to do is to change the above switch statement to

  retval = argx.nth_element (n, dim);

and then define

  octave_value
  octave_value::nth_element (const idx_vector& n, int dim) const
  {
    return rep->nth_element (n, dim);
  }

in ov.h,

  virtual octave_value
  octave_base_value::nth_element (const idx_vector& n, int dim) conts;

in ov-base.h,

  octave_value
  octave_base_value::nth_element (const idx_vector& n, int dim)
  {
    gripe_wrong_type_arg ("octave_base_value::nth_element", type_name ());
  }

in ov-base.cc, and corresponding functions for each class that should
define this function.   The cellstr case belongs in ov-cell.cc.

I don't know of a simpler way to do this.

Mapper functions are similar, but reduce to repeated application of a
simple non-member function.  For those, we thought about doing the
same as I outline above but decided to use a generic map function in
the octave_value hierarchy and to switch on the type of map inside the
map function for each specific value type (for example, see
octave_matrix::map in ov-re-mat.cc).

Maybe a similar strategy could be used for sum, cumsum, prod, cumprod,
nth_element, etc. to abstract them all into one "reduction" function,
but these functions ultimately call member functions, so I'm not sure
how to handle that in a clean way with function pointers.  Maybe there
is a template trick I'm not seeing at the moment.

How many of these functions are there that have this kind of switch
statement?

jwe


reply via email to

[Prev in Thread] Current Thread [Next in Thread]