1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2013-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_hook_fcn_h)
27 #define octave_hook_fcn_h 1
28 
29 #include "octave-config.h"
30 
31 #include <string>
32 
33 #include "ovl.h"
34 #include "ov.h"
35 #include "ov-fcn-handle.h"
36 #include "variables.h"
37 
38 class
39 base_hook_function
40 {
41 public:
42 
43   friend class hook_function;
44 
base_hook_function(void)45   base_hook_function (void) : count (1) { }
46 
base_hook_function(const base_hook_function &)47   base_hook_function (const base_hook_function&) : count (1) { }
48 
49   virtual ~base_hook_function (void) = default;
50 
id(void)51   virtual std::string id (void) const { return ""; }
52 
is_valid(void)53   virtual bool is_valid (void) const { return false; }
54 
eval(const octave_value_list &)55   virtual void eval (const octave_value_list&) { }
56 
57 protected:
58 
59   std::size_t count;
60 };
61 
62 class
63 hook_function
64 {
65 public:
66 
hook_function(void)67   hook_function (void)
68   {
69     static base_hook_function nil_rep;
70     rep = &nil_rep;
71     rep->count++;
72   }
73 
74   hook_function (const octave_value& f,
75                  const octave_value& d = octave_value ());
76 
~hook_function(void)77   ~hook_function (void)
78   {
79     if (--rep->count == 0)
80       delete rep;
81   }
82 
hook_function(const hook_function & hf)83   hook_function (const hook_function& hf)
84     : rep (hf.rep)
85   {
86     rep->count++;
87   }
88 
89   hook_function& operator = (const hook_function& hf)
90   {
91     if (rep != hf.rep)
92       {
93         if (--rep->count == 0)
94           delete rep;
95 
96         rep = hf.rep;
97         rep->count++;
98       }
99 
100     return *this;
101   }
102 
id(void)103   std::string id (void) const { return rep->id (); }
104 
is_valid(void)105   bool is_valid (void) const { return rep->is_valid (); }
106 
eval(const octave_value_list & initial_args)107   void eval (const octave_value_list& initial_args)
108   {
109     rep->eval (initial_args);
110   }
111 
112 private:
113 
114   base_hook_function *rep;
115 };
116 
117 class
118 named_hook_function : public base_hook_function
119 {
120 public:
121 
named_hook_function(const std::string & n,const octave_value & d)122   named_hook_function (const std::string& n, const octave_value& d)
123     : name (n), data (d)
124   { }
125 
126   void eval (const octave_value_list& initial_args);
127 
id(void)128   std::string id (void) const { return name; }
129 
is_valid(void)130   bool is_valid (void) const { return is_valid_function (name); }
131 
132 private:
133 
134   std::string name;
135 
136   octave_value data;
137 };
138 
139 class
140 fcn_handle_hook_function : public base_hook_function
141 {
142 public:
143 
fcn_handle_hook_function(const octave_value & fh_arg,const octave_value & d)144   fcn_handle_hook_function (const octave_value& fh_arg, const octave_value& d)
145     : ident (), valid (false), fcn_handle (fh_arg), data (d)
146   {
147     octave_fcn_handle *fh = fcn_handle.fcn_handle_value (true);
148 
149     if (fh)
150       {
151         valid = true;
152 
153         std::ostringstream buf;
154         buf << fh;
155         ident = fh->fcn_name () + ':' + buf.str ();
156       }
157   }
158 
159   void eval (const octave_value_list& initial_args);
160 
id(void)161   std::string id (void) const { return ident; }
162 
is_valid(void)163   bool is_valid (void) const { return valid; }
164 
165 private:
166 
167   std::string ident;
168 
169   bool valid;
170 
171   octave_value fcn_handle;
172 
173   octave_value data;
174 };
175 
176 class
177 hook_function_list
178 {
179 public:
180 
181   typedef std::map<std::string, hook_function> map_type;
182 
183   typedef map_type::iterator iterator;
184   typedef map_type::const_iterator const_iterator;
185 
hook_function_list(void)186   hook_function_list (void) : fcn_map () { }
187 
188   ~hook_function_list (void) = default;
189 
hook_function_list(const hook_function_list & lst)190   hook_function_list (const hook_function_list& lst)
191     : fcn_map (lst.fcn_map)
192   { }
193 
194   hook_function_list& operator = (const hook_function_list& lst)
195   {
196     if (&lst != this)
197       fcn_map = lst.fcn_map;
198 
199     return *this;
200   }
201 
empty(void)202   bool empty (void) const { return fcn_map.empty (); }
203 
clear(void)204   void clear (void) { fcn_map.clear (); }
205 
insert(const std::string & id,const hook_function & f)206   void insert (const std::string& id, const hook_function& f)
207   {
208     fcn_map[id] = f;
209   }
210 
find(const std::string & id)211   iterator find (const std::string& id)
212   {
213     return fcn_map.find (id);
214   }
215 
find(const std::string & id)216   const_iterator find (const std::string& id) const
217   {
218     return fcn_map.find (id);
219   }
220 
end(void)221   iterator end (void) { return fcn_map.end (); }
222 
end(void)223   const_iterator end (void) const { return fcn_map.end (); }
224 
erase(iterator p)225   void erase (iterator p) { fcn_map.erase (p); }
226 
227   void run (const octave_value_list& initial_args = octave_value_list ())
228   {
229     auto p = fcn_map.begin ();
230 
231     while (p != fcn_map.end ())
232       {
233         std::string hook_fcn_id = p->first;
234         hook_function hook_fcn = p->second;
235 
236         auto q = p++;
237 
238         if (hook_fcn.is_valid ())
239           hook_fcn.eval (initial_args);
240         else
241           fcn_map.erase (q);
242       }
243   }
244 
245 private:
246 
247   map_type fcn_map;
248 };
249 
250 #endif
251