comparison src/ov-fcn-handle.cc @ 10960:409ceee18acc

binders optimization
author Jaroslav Hajek <highegg@gmail.com>
date Fri, 10 Sep 2010 11:48:41 +0200
parents f1a45913662a
children 2cc9b08bfd39
comparison
equal deleted inserted replaced
10959:4f46520e2103 10960:409ceee18acc
1 /* 1 /*
2 2
3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 John W. Eaton 3 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 John W. Eaton
4 Copyright (C) 2009 VZLU Prague, a.s. 4 Copyright (C) 2009 VZLU Prague, a.s.
5 Copyright (C) 2010 Jaroslav Hajek
5 6
6 This file is part of Octave. 7 This file is part of Octave.
7 8
8 Octave is free software; you can redistribute it and/or modify it 9 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the 10 under the terms of the GNU General Public License as published by the
45 #include "pt-misc.h" 46 #include "pt-misc.h"
46 #include "pt-stmt.h" 47 #include "pt-stmt.h"
47 #include "pt-cmd.h" 48 #include "pt-cmd.h"
48 #include "pt-exp.h" 49 #include "pt-exp.h"
49 #include "pt-assign.h" 50 #include "pt-assign.h"
51 #include "pt-arg-list.h"
50 #include "variables.h" 52 #include "variables.h"
51 #include "parse.h" 53 #include "parse.h"
52 #include "unwind-prot.h" 54 #include "unwind-prot.h"
53 #include "defaults.h" 55 #include "defaults.h"
54 #include "file-stat.h" 56 #include "file-stat.h"
1754 %! y = testrecursionfunc (@(x) f(2*x), x, n); 1756 %! y = testrecursionfunc (@(x) f(2*x), x, n);
1755 %! endif 1757 %! endif
1756 %!test 1758 %!test
1757 %! assert (testrecursionfunc (@(x) x, 1), 8); 1759 %! assert (testrecursionfunc (@(x) x, 1), 8);
1758 */ 1760 */
1761
1762 octave_fcn_binder::octave_fcn_binder (const octave_value& f,
1763 const octave_value& root,
1764 const octave_value_list& templ,
1765 const std::vector<int>& mask,
1766 int exp_nargin)
1767 : octave_fcn_handle (f), root_handle (root), arg_template (templ),
1768 arg_mask (mask), expected_nargin (exp_nargin)
1769 {
1770 }
1771
1772 octave_fcn_handle *
1773 octave_fcn_binder::maybe_binder (const octave_value& f)
1774 {
1775 octave_fcn_handle *retval = 0;
1776
1777 octave_user_function *usr_fcn = f.user_function_value (false);
1778 tree_parameter_list *param_list = usr_fcn ? usr_fcn->parameter_list () : 0;
1779
1780 // Verify that the body is a single expression (always true in theory).
1781
1782 tree_statement_list *cmd_list = usr_fcn ? usr_fcn->body () : 0;
1783 tree_expression *body_expr = (cmd_list->length () == 1
1784 ? cmd_list->front ()->expression () : 0);
1785
1786
1787 if (body_expr && body_expr->is_index_expression ()
1788 && ! (param_list && param_list->takes_varargs ()))
1789 {
1790 // It's an index expression.
1791 tree_index_expression *idx_expr = dynamic_cast<tree_index_expression *> (body_expr);
1792 tree_expression *head_expr = idx_expr->expression ();
1793 std::list<tree_argument_list *> arg_lists = idx_expr->arg_lists ();
1794 std::string type_tags = idx_expr->type_tags ();
1795
1796 if (type_tags.length () == 1 && type_tags[0] == '('
1797 && head_expr->is_identifier ())
1798 {
1799 assert (arg_lists.size () == 1);
1800
1801 // It's a single index expression: a(x,y,....)
1802 tree_identifier *head_id = dynamic_cast<tree_identifier *> (head_expr);
1803 tree_argument_list *arg_list = arg_lists.front ();
1804
1805 // Build a map of input params to their position.
1806 std::map<std::string, int> arginmap;
1807 int npar = 0;
1808
1809 if (param_list)
1810 {
1811 for (tree_parameter_list::iterator it = param_list->begin ();
1812 it != param_list->end (); ++it, ++npar)
1813 {
1814 tree_decl_elt *elt = *it;
1815 tree_identifier *id = elt ? elt->ident () : 0;
1816 if (id && ! id->is_black_hole ())
1817 arginmap[id->name ()] = npar;
1818 }
1819 }
1820
1821 if (arg_list && arg_list->length () > 0)
1822 {
1823 bool bad = false;
1824 int nargs = arg_list->length ();
1825 octave_value_list arg_template (nargs);
1826 std::vector<int> arg_mask (nargs);
1827
1828 // Verify that each argument is either a named param, a constant, or a defined identifier.
1829 int iarg = 0;
1830 for (tree_argument_list::iterator it = arg_list->begin ();
1831 it != arg_list->end (); ++it, ++iarg)
1832 {
1833 tree_expression *elt = *it;
1834 if (elt && elt->is_constant ())
1835 {
1836 arg_template(iarg) = elt->rvalue1 ();
1837 arg_mask[iarg] = -1;
1838 }
1839 else if (elt && elt->is_identifier ())
1840 {
1841 tree_identifier *elt_id = dynamic_cast<tree_identifier *> (elt);
1842 if (arginmap.find (elt_id->name ()) != arginmap.end ())
1843 {
1844 arg_mask[iarg] = arginmap[elt_id->name ()];
1845 }
1846 else if (elt_id->is_defined ())
1847 {
1848 arg_template(iarg) = elt_id->rvalue1 ();
1849 arg_mask[iarg] = -1;
1850 }
1851 else
1852 {
1853 bad = true;
1854 break;
1855 }
1856 }
1857 else
1858 {
1859 bad = true;
1860 break;
1861 }
1862 }
1863
1864 octave_value root_val;
1865
1866 if (! bad)
1867 {
1868 // If the head is a value, use it as root.
1869 if (head_id->is_defined ())
1870 root_val = head_id->rvalue1 ();
1871 else
1872 {
1873 // It's a name.
1874 std::string head_name = head_id->name ();
1875 // Function handles can't handle legacy dispatch, so
1876 // we make sure it's not defined.
1877 if (symbol_table::get_dispatch (head_name).size () > 0)
1878 bad = true;
1879 else
1880 {
1881 // Simulate try/catch.
1882 // FIXME: there should be a method for that.
1883 unwind_protect frame;
1884
1885 frame.protect_var (error_state);
1886 frame.protect_var (buffer_error_messages);
1887 frame.protect_var (Vdebug_on_error);
1888 frame.protect_var (Vdebug_on_warning);
1889
1890 buffer_error_messages++;
1891 Vdebug_on_error = false;
1892 Vdebug_on_warning = false;
1893
1894 root_val = make_fcn_handle (head_name);
1895 if (error_state)
1896 bad = true;
1897 }
1898 }
1899 }
1900
1901 if (! bad)
1902 {
1903 retval = new octave_fcn_binder (f, root_val, arg_template,
1904 arg_mask, npar);
1905 }
1906 }
1907 }
1908 }
1909
1910 if (! retval)
1911 retval = new octave_fcn_handle (f, octave_fcn_handle::anonymous);
1912
1913 return retval;
1914 }
1915
1916 octave_value_list
1917 octave_fcn_binder::do_multi_index_op (int nargout,
1918 const octave_value_list& args)
1919 {
1920 return do_multi_index_op (nargout, args, 0);
1921 }
1922
1923 octave_value_list
1924 octave_fcn_binder::do_multi_index_op (int nargout,
1925 const octave_value_list& args,
1926 const std::list<octave_lvalue>* lvalue_list)
1927 {
1928 octave_value_list retval;
1929
1930 if (args.length () == expected_nargin)
1931 {
1932 for (int i = 0; i < arg_template.length (); i++)
1933 {
1934 int j = arg_mask[i];
1935 if (j >= 0)
1936 arg_template.xelem(i) = args(j);
1937 }
1938
1939 retval = root_handle.do_multi_index_op (nargout, arg_template, lvalue_list);
1940 }
1941 else
1942 retval = octave_fcn_handle::do_multi_index_op (nargout, args, lvalue_list);
1943
1944 return retval;
1945 }