Mercurial > hg > octave-nkf
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 } |