view libinterp/octave-value/ov-typeinfo.cc @ 20939:b17fda023ca6

maint: Use new C++ archetype in more files. Place input validation first in files. Move declaration of retval down in function to be closer to point of usage. Eliminate else clause after if () error. Use "return ovl()" where it makes sense. * find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, givens.cc, graphics.cc, help.cc, hess.cc, hex2num.cc, input.cc, kron.cc, load-path.cc, load-save.cc, lookup.cc, mappers.cc, matrix_type.cc, mgorth.cc, nproc.cc, ordschur.cc, pager.cc, pinv.cc, pr-output.cc, profiler.cc, psi.cc, quad.cc, rcond.cc, regexp.cc, schur.cc, sighandlers.cc, sparse.cc, str2double.cc, strfind.cc, strfns.cc, sub2ind.cc, svd.cc, sylvester.cc, symtab.cc, syscalls.cc, sysdep.cc, time.cc, toplev.cc, tril.cc, tsearch.cc, typecast.cc, urlwrite.cc, utils.cc, variables.cc, __delaunayn__.cc, __eigs__.cc, __glpk__.cc, __magick_read__.cc, __osmesa_print__.cc, __voronoi__.cc, amd.cc, audiodevinfo.cc, audioread.cc, chol.cc, colamd.cc, dmperm.cc, fftw.cc, qr.cc, symbfact.cc, symrcm.cc, ov-bool-mat.cc, ov-cell.cc, ov-class.cc, ov-classdef.cc, ov-fcn-handle.cc, ov-fcn-inline.cc, ov-flt-re-mat.cc, ov-java.cc, ov-null-mat.cc, ov-oncleanup.cc, ov-re-mat.cc, ov-struct.cc, ov-typeinfo.cc, ov-usr-fcn.cc, ov.cc, octave.cc: Use new C++ archetype in more files.
author Rik <rik@octave.org>
date Fri, 18 Dec 2015 15:37:22 -0800
parents 1142cf6abc0d
children 850e3d2533d4
line wrap: on
line source

/*

Copyright (C) 1996-2015 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "Array.h"
#include "singleton-cleanup.h"

#include "defun.h"
#include "error.h"
#include "ov-typeinfo.h"

const int
octave_value_typeinfo::init_tab_sz (16);

octave_value_typeinfo *
octave_value_typeinfo::instance (0);

bool
octave_value_typeinfo::instance_ok (void)
{
  bool retval = true;

  if (! instance)
    {
      instance = new octave_value_typeinfo ();

      if (instance)
        singleton_cleanup_list::add (cleanup_instance);
    }

  if (! instance)
    {
      error ("unable to create value type info object!");

      retval = false;
    }

  return retval;
}

int
octave_value_typeinfo::register_type (const std::string& t_name,
                                      const std::string& c_name,
                                      const octave_value& val)
{
  return (instance_ok ())
         ? instance->do_register_type (t_name, c_name, val) : -1;
}

bool
octave_value_typeinfo::register_unary_class_op (octave_value::unary_op op,
                                                octave_value_typeinfo::unary_class_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_unary_class_op (op, f) : false;
}

bool
octave_value_typeinfo::register_unary_op (octave_value::unary_op op,
                                          int t,
                                          octave_value_typeinfo::unary_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_unary_op (op, t, f) : false;
}

bool
octave_value_typeinfo::register_non_const_unary_op (octave_value::unary_op op,
                                                    int t,
                                                    octave_value_typeinfo::non_const_unary_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_non_const_unary_op (op, t, f) : false;
}

bool
octave_value_typeinfo::register_binary_class_op (octave_value::binary_op op,
                                                 octave_value_typeinfo::binary_class_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_binary_class_op (op, f) : false;
}

bool
octave_value_typeinfo::register_binary_op (octave_value::binary_op op,
                                           int t1, int t2,
                                           octave_value_typeinfo::binary_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_binary_op (op, t1, t2, f) : false;
}

bool
octave_value_typeinfo::register_binary_class_op (octave_value::compound_binary_op op,
                                                 octave_value_typeinfo::binary_class_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_binary_class_op (op, f) : false;
}

bool
octave_value_typeinfo::register_binary_op (octave_value::compound_binary_op op,
                                           int t1, int t2,
                                           octave_value_typeinfo::binary_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_binary_op (op, t1, t2, f) : false;
}

bool
octave_value_typeinfo::register_cat_op (int t1, int t2,
                                        octave_value_typeinfo::cat_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_cat_op (t1, t2, f) : false;
}

bool
octave_value_typeinfo::register_assign_op (octave_value::assign_op op,
                                           int t_lhs, int t_rhs,
                                           octave_value_typeinfo::assign_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_assign_op (op, t_lhs, t_rhs, f) : -1;
}

bool
octave_value_typeinfo::register_assignany_op (octave_value::assign_op op,
                                              int t_lhs, octave_value_typeinfo::assignany_op_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_assignany_op (op, t_lhs, f) : -1;
}

bool
octave_value_typeinfo::register_pref_assign_conv (int t_lhs, int t_rhs,
                                                  int t_result)
{
  return (instance_ok ())
         ? instance->do_register_pref_assign_conv (t_lhs, t_rhs, t_result)
         : false;
}

bool
octave_value_typeinfo::register_type_conv_op (int t, int t_result,
                                              octave_base_value::type_conv_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_type_conv_op (t, t_result, f) : false;
}

bool
octave_value_typeinfo::register_widening_op (int t, int t_result,
                                             octave_base_value::type_conv_fcn f)
{
  return (instance_ok ())
         ? instance->do_register_widening_op (t, t_result, f) : false;
}

// FIXME: we should also store all class names and provide a
// way to list them (calling class with nargin == 0?).

int
octave_value_typeinfo::do_register_type (const std::string& t_name,
                                         const std::string& /* c_name */,
                                         const octave_value& val)
{
  int i = 0;

  for (i = 0; i < num_types; i++)
    if (t_name == types (i))
      return i;

  int len = types.numel ();

  if (i == len)
    {
      len *= 2;

      types.resize (dim_vector (len, 1), std::string ());

      vals.resize (dim_vector (len, 1), octave_value ());

      unary_ops.resize (dim_vector (octave_value::num_unary_ops, len), 0);

      non_const_unary_ops.resize
        (dim_vector (octave_value::num_unary_ops, len), 0);

      binary_ops.resize
        (dim_vector (octave_value::num_binary_ops, len, len), 0);

      compound_binary_ops.resize
        (dim_vector (octave_value::num_compound_binary_ops, len, len), 0);

      cat_ops.resize (dim_vector (len, len), 0);

      assign_ops.resize
        (dim_vector (octave_value::num_assign_ops, len, len), 0);

      assignany_ops.resize
        (dim_vector (octave_value::num_assign_ops, len), 0);

      pref_assign_conv.resize (dim_vector (len, len), -1);

      type_conv_ops.resize (dim_vector (len, len), 0);

      widening_ops.resize (dim_vector (len, len), 0);
    }

  types (i) = t_name;

  vals (i) = val;

  num_types++;

  return i;
}

bool
octave_value_typeinfo::do_register_unary_class_op (octave_value::unary_op op,
                                                   octave_value_typeinfo::unary_class_op_fcn f)
{
  if (lookup_unary_class_op (op))
    {
      std::string op_name = octave_value::unary_op_as_string (op);

      warning ("duplicate unary operator '%s' for class dispatch",
               op_name.c_str ());
    }

  unary_class_ops.checkelem (static_cast<int> (op))
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_unary_op (octave_value::unary_op op,
                                             int t,
                                             octave_value_typeinfo::unary_op_fcn f)
{
  if (lookup_unary_op (op, t))
    {
      std::string op_name = octave_value::unary_op_as_string (op);
      std::string type_name = types(t);

      warning ("duplicate unary operator '%s' for type '%s'",
               op_name.c_str (), type_name.c_str ());
    }

  unary_ops.checkelem (static_cast<int> (op), t) = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_non_const_unary_op
  (octave_value::unary_op op, int t,
   octave_value_typeinfo::non_const_unary_op_fcn f)
{
  if (lookup_non_const_unary_op (op, t))
    {
      std::string op_name = octave_value::unary_op_as_string (op);
      std::string type_name = types(t);

      warning ("duplicate unary operator '%s' for type '%s'",
               op_name.c_str (), type_name.c_str ());
    }

  non_const_unary_ops.checkelem (static_cast<int> (op), t)
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_binary_class_op (octave_value::binary_op op,
                                                    octave_value_typeinfo::binary_class_op_fcn f)
{
  if (lookup_binary_class_op (op))
    {
      std::string op_name = octave_value::binary_op_as_string (op);

      warning ("duplicate binary operator '%s' for class dispatch",
               op_name.c_str ());
    }

  binary_class_ops.checkelem (static_cast<int> (op))
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_binary_op (octave_value::binary_op op,
                                              int t1, int t2,
                                              octave_value_typeinfo::binary_op_fcn f)
{
  if (lookup_binary_op (op, t1, t2))
    {
      std::string op_name = octave_value::binary_op_as_string (op);
      std::string t1_name = types(t1);
      std::string t2_name = types(t2);

      warning ("duplicate binary operator '%s' for types '%s' and '%s'",
               op_name.c_str (), t1_name.c_str (), t1_name.c_str ());
    }

  binary_ops.checkelem (static_cast<int> (op), t1, t2)
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_binary_class_op (octave_value::compound_binary_op op,
                                                    octave_value_typeinfo::binary_class_op_fcn f)
{
  if (lookup_binary_class_op (op))
    {
      std::string op_name = octave_value::binary_op_fcn_name (op);

      warning ("duplicate compound binary operator '%s' for class dispatch",
               op_name.c_str ());
    }

  compound_binary_class_ops.checkelem (static_cast<int> (op))
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_binary_op (octave_value::compound_binary_op op,
                                              int t1, int t2,
                                              octave_value_typeinfo::binary_op_fcn f)
{
  if (lookup_binary_op (op, t1, t2))
    {
      std::string op_name = octave_value::binary_op_fcn_name (op);
      std::string t1_name = types(t1);
      std::string t2_name = types(t2);

      warning ("duplicate compound binary operator '%s' for types '%s' and '%s'",
               op_name.c_str (), t1_name.c_str (), t1_name.c_str ());
    }

  compound_binary_ops.checkelem (static_cast<int> (op), t1, t2)
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_cat_op (int t1, int t2,
                                           octave_value_typeinfo::cat_op_fcn f)
{
  if (lookup_cat_op (t1, t2))
    {
      std::string t1_name = types(t1);
      std::string t2_name = types(t2);

      warning ("duplicate concatenation operator for types '%s' and '%s'",
               t1_name.c_str (), t1_name.c_str ());
    }

  cat_ops.checkelem (t1, t2) = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_assign_op (octave_value::assign_op op,
                                              int t_lhs, int t_rhs,
                                              octave_value_typeinfo::assign_op_fcn f)
{
  if (lookup_assign_op (op, t_lhs, t_rhs))
    {
      std::string op_name = octave_value::assign_op_as_string (op);
      std::string t_lhs_name = types(t_lhs);
      std::string t_rhs_name = types(t_rhs);

      warning ("duplicate assignment operator '%s' for types '%s' and '%s'",
               op_name.c_str (), t_lhs_name.c_str (), t_rhs_name.c_str ());
    }

  assign_ops.checkelem (static_cast<int> (op), t_lhs, t_rhs)
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_assignany_op (octave_value::assign_op op,
                                                 int t_lhs, octave_value_typeinfo::assignany_op_fcn f)
{
  if (lookup_assignany_op (op, t_lhs))
    {
      std::string op_name = octave_value::assign_op_as_string (op);
      std::string t_lhs_name = types(t_lhs);

      warning ("duplicate assignment operator '%s' for types '%s'",
               op_name.c_str (), t_lhs_name.c_str ());
    }

  assignany_ops.checkelem (static_cast<int> (op), t_lhs)
    = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_pref_assign_conv (int t_lhs, int t_rhs,
                                                     int t_result)
{
  if (lookup_pref_assign_conv (t_lhs, t_rhs) >= 0)
    {
      std::string t_lhs_name = types(t_lhs);
      std::string t_rhs_name = types(t_rhs);

      warning ("overriding assignment conversion for types '%s' and '%s'",
               t_lhs_name.c_str (), t_rhs_name.c_str ());
    }

  pref_assign_conv.checkelem (t_lhs, t_rhs) = t_result;

  return false;
}

bool
octave_value_typeinfo::do_register_type_conv_op
  (int t, int t_result, octave_base_value::type_conv_fcn f)
{
  if (lookup_type_conv_op (t, t_result))
    {
      std::string t_name = types(t);
      std::string t_result_name = types(t_result);

      warning ("overriding type conversion op for '%s' to '%s'",
               t_name.c_str (), t_result_name.c_str ());
    }

  type_conv_ops.checkelem (t, t_result) = reinterpret_cast<void *> (f);

  return false;
}

bool
octave_value_typeinfo::do_register_widening_op
  (int t, int t_result, octave_base_value::type_conv_fcn f)
{
  if (lookup_widening_op (t, t_result))
    {
      std::string t_name = types(t);
      std::string t_result_name = types(t_result);

      warning ("overriding widening op for '%s' to '%s'",
               t_name.c_str (), t_result_name.c_str ());
    }

  widening_ops.checkelem (t, t_result) = reinterpret_cast<void *> (f);

  return false;
}

octave_value
octave_value_typeinfo::do_lookup_type (const std::string& nm)
{
  octave_value retval;

  for (int i = 0; i < num_types; i++)
    {
      if (nm == types(i))
        {
          retval = vals(i);
          retval.make_unique ();
          break;
        }
    }

  return retval;
}

octave_value_typeinfo::unary_class_op_fcn
octave_value_typeinfo::do_lookup_unary_class_op (octave_value::unary_op op)
{
  void *f = unary_class_ops.checkelem (static_cast<int> (op));
  return reinterpret_cast<octave_value_typeinfo::unary_class_op_fcn> (f);
}

octave_value_typeinfo::unary_op_fcn
octave_value_typeinfo::do_lookup_unary_op (octave_value::unary_op op, int t)
{
  void *f = unary_ops.checkelem (static_cast<int> (op), t);
  return reinterpret_cast<octave_value_typeinfo::unary_op_fcn> (f);
}

octave_value_typeinfo::non_const_unary_op_fcn
octave_value_typeinfo::do_lookup_non_const_unary_op
  (octave_value::unary_op op, int t)
{
  void *f = non_const_unary_ops.checkelem (static_cast<int> (op), t);
  return reinterpret_cast<octave_value_typeinfo::non_const_unary_op_fcn> (f);
}

octave_value_typeinfo::binary_class_op_fcn
octave_value_typeinfo::do_lookup_binary_class_op (octave_value::binary_op op)
{
  void *f = binary_class_ops.checkelem (static_cast<int> (op));
  return reinterpret_cast<octave_value_typeinfo::binary_class_op_fcn> (f);
}

octave_value_typeinfo::binary_op_fcn
octave_value_typeinfo::do_lookup_binary_op (octave_value::binary_op op,
                                            int t1, int t2)
{
  void *f = binary_ops.checkelem (static_cast<int> (op), t1, t2);
  return reinterpret_cast<octave_value_typeinfo::binary_op_fcn> (f);
}

octave_value_typeinfo::binary_class_op_fcn
octave_value_typeinfo::do_lookup_binary_class_op (octave_value::compound_binary_op op)
{
  void *f = compound_binary_class_ops.checkelem (static_cast<int> (op));
  return reinterpret_cast<octave_value_typeinfo::binary_class_op_fcn> (f);
}

octave_value_typeinfo::binary_op_fcn
octave_value_typeinfo::do_lookup_binary_op (octave_value::compound_binary_op op,
                                            int t1, int t2)
{
  void *f = compound_binary_ops.checkelem (static_cast<int> (op), t1, t2);
  return reinterpret_cast<octave_value_typeinfo::binary_op_fcn> (f);
}

octave_value_typeinfo::cat_op_fcn
octave_value_typeinfo::do_lookup_cat_op (int t1, int t2)
{
  void *f = cat_ops.checkelem (t1, t2);
  return reinterpret_cast<octave_value_typeinfo::cat_op_fcn> (f);
}

octave_value_typeinfo::assign_op_fcn
octave_value_typeinfo::do_lookup_assign_op (octave_value::assign_op op,
                                            int t_lhs, int t_rhs)
{
  void *f = assign_ops.checkelem (static_cast<int> (op), t_lhs, t_rhs);
  return reinterpret_cast<octave_value_typeinfo::assign_op_fcn> (f);
}

octave_value_typeinfo::assignany_op_fcn
octave_value_typeinfo::do_lookup_assignany_op (octave_value::assign_op op,
                                               int t_lhs)
{
  void *f = assignany_ops.checkelem (static_cast<int> (op), t_lhs);
  return reinterpret_cast<octave_value_typeinfo::assignany_op_fcn> (f);
}

int
octave_value_typeinfo::do_lookup_pref_assign_conv (int t_lhs, int t_rhs)
{
  return pref_assign_conv.checkelem (t_lhs, t_rhs);
}

octave_base_value::type_conv_fcn
octave_value_typeinfo::do_lookup_type_conv_op (int t, int t_result)
{
  void *f = type_conv_ops.checkelem (t, t_result);
  return reinterpret_cast<octave_base_value::type_conv_fcn> (f);
}

octave_base_value::type_conv_fcn
octave_value_typeinfo::do_lookup_widening_op (int t, int t_result)
{
  void *f = widening_ops.checkelem (t, t_result);
  return reinterpret_cast<octave_base_value::type_conv_fcn> (f);
}

string_vector
octave_value_typeinfo::do_installed_type_names (void)
{
  string_vector retval (num_types);

  for (int i = 0; i < num_types; i++)
    retval(i) = types(i);

  return retval;
}

DEFUN (typeinfo, args, ,
       "-*- texinfo -*-\n\
@deftypefn  {} {} typeinfo ()\n\
@deftypefnx {} {} typeinfo (@var{expr})\n\
\n\
Return the type of the expression @var{expr}, as a string.\n\
\n\
If @var{expr} is omitted, return a cell array of strings containing all the\n\
currently installed data types.\n\
@seealso{class, isa}\n\
@end deftypefn")
{
  int nargin = args.length ();

  if (nargin > 1)
    print_usage ();

  if (nargin == 0)
    return ovl (Cell (octave_value_typeinfo::installed_type_names ()));
  else
    return ovl (args(0).type_name ());
}

/*
%!assert (iscellstr (typeinfo ()))

%!assert (typeinfo ({"cell"}), "cell")

%!assert (typeinfo (1), "scalar")
%!assert (typeinfo (double (1)), "scalar")
%!assert (typeinfo (i), "complex scalar")

%!assert (typeinfo ([1, 2]), "matrix")
%!assert (typeinfo (double ([1, 2])), "matrix")
%!assert (typeinfo (diag ([1, 2])), "diagonal matrix")
%!assert (typeinfo ([i, 2]), "complex matrix")
%!assert (typeinfo (diag ([i, 2])), "complex diagonal matrix")

%!assert (typeinfo (1:2), "range")

%!assert (typeinfo (false), "bool")
%!assert (typeinfo ([true, false]), "bool matrix")

%!assert (typeinfo ("string"), "string")
%!assert (typeinfo ('string'), "sq_string")

%!assert (typeinfo (int8 (1)), "int8 scalar")
%!assert (typeinfo (int16 (1)), "int16 scalar")
%!assert (typeinfo (int32 (1)), "int32 scalar")
%!assert (typeinfo (int64 (1)), "int64 scalar")
%!assert (typeinfo (uint8 (1)), "uint8 scalar")
%!assert (typeinfo (uint16 (1)), "uint16 scalar")
%!assert (typeinfo (uint32 (1)), "uint32 scalar")
%!assert (typeinfo (uint64 (1)), "uint64 scalar")

%!assert (typeinfo (int8 ([1,2])), "int8 matrix")
%!assert (typeinfo (int16 ([1,2])), "int16 matrix")
%!assert (typeinfo (int32 ([1,2])), "int32 matrix")
%!assert (typeinfo (int64 ([1,2])), "int64 matrix")
%!assert (typeinfo (uint8 ([1,2])), "uint8 matrix")
%!assert (typeinfo (uint16 ([1,2])), "uint16 matrix")
%!assert (typeinfo (uint32 ([1,2])), "uint32 matrix")
%!assert (typeinfo (uint64 ([1,2])), "uint64 matrix")

%!assert (typeinfo (sparse ([true, false])), "sparse bool matrix")
%!assert (typeinfo (logical (sparse (i * eye (10)))), "sparse bool matrix")
%!assert (typeinfo (sparse ([1,2])), "sparse matrix")
%!assert (typeinfo (sparse (eye (10))), "sparse matrix")
%!assert (typeinfo (sparse ([i,2])), "sparse complex matrix")
%!assert (typeinfo (sparse (i * eye (10))), "sparse complex matrix")

%!test
%! s(2).a = 1;
%! assert (typeinfo (s), "struct");

%!test
%! s.a = 1;
%! assert (typeinfo (s), "scalar struct");

## FIXME: This doesn't work as a test for comma-separated list
%!#test
%! clist = {1, 2, 3};
%! assert (typeinfo (clist{:}), "cs-list");

%!assert (typeinfo (@sin), "function handle")
%!assert (typeinfo (@(x) x), "function handle")

%!assert (typeinfo (inline ("x^2")), "inline function")

%!assert (typeinfo (single (1)), "float scalar")
%!assert (typeinfo (single (i)), "float complex scalar")
%!assert (typeinfo (single ([1, 2])), "float matrix")

%!assert (typeinfo (single (diag ([1, 2]))), "float diagonal matrix")
%!assert (typeinfo (diag (single ([1, 2]))), "float diagonal matrix")
%!assert (typeinfo (single (diag ([i, 2]))), "float complex diagonal matrix")
%!assert (typeinfo (diag (single ([i, 2]))), "float complex diagonal matrix")

%!assert (typeinfo (eye(3)(:,[1 3 2])), "permutation matrix")
%!test
%! [l, u, p] = lu (rand (3));
%! assert (typeinfo (p), "permutation matrix");

%!assert (typeinfo ([]), "null_matrix")
%!assert (typeinfo (""), "null_string")
%!assert (typeinfo (''), "null_sq_string")

%!test
%! cvar = onCleanup (@() "");
%! assert (typeinfo (cvar), "onCleanup");

%!testif HAVE_JAVA
%! x = javaObject ("java.lang.StringBuffer");
%! assert (typeinfo (x), "octave_java");

## Test input validation
%!error typeinfo ("foo", 1)
*/