Daily bump.
[platform/upstream/gcc.git] / libcc1 / rpc.hh
1 /* RPC call and callback templates
2    Copyright (C) 2014-2022 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19
20 #ifndef CC1_PLUGIN_RPC_HH
21 #define CC1_PLUGIN_RPC_HH
22
23 #include "status.hh"
24 #include "connection.hh"
25 #include "deleter.hh"
26
27 namespace cc1_plugin
28 {
29   // The plugin API may contain some "const" method parameters.
30   // However, when unmarshalling we cannot unmarshall into a const
31   // object; and furthermore we want to be able to deallocate pointers
32   // when finished with them.  This wrapper class lets us properly
33   // remove the "const" and handle deallocation from pointer types.
34
35   template<typename T>
36   class argument_wrapper
37   {
38   public:
39
40     argument_wrapper () { }
41     ~argument_wrapper () { }
42
43     argument_wrapper (const argument_wrapper &) = delete;
44     argument_wrapper &operator= (const argument_wrapper &) = delete;
45
46     T get () const { return m_object; }
47
48     status unmarshall (connection *conn)
49     {
50       return ::cc1_plugin::unmarshall (conn, &m_object);
51     }
52
53   private:
54
55     T m_object;
56   };
57
58   // Specialization for any kind of pointer.
59   template<typename T>
60   class argument_wrapper<T *>
61   {
62   public:
63     argument_wrapper () = default;
64     ~argument_wrapper () = default;
65
66     argument_wrapper (const argument_wrapper &) = delete;
67     argument_wrapper &operator= (const argument_wrapper &) = delete;
68
69     typedef typename std::remove_const<T>::type type;
70
71     const type *get () const
72     {
73       return m_object.get ();
74     }
75
76     status unmarshall (connection *conn)
77     {
78       type *ptr;
79       if (!::cc1_plugin::unmarshall (conn, &ptr))
80         return FAIL;
81       m_object.reset (ptr);
82       return OK;
83     }
84
85   private:
86
87     unique_ptr<type> m_object;
88   };
89
90   // There are two kinds of template functions here: "call" and
91   // "invoker".
92
93   // The "call" template is used for making a remote procedure call.
94   // It starts a query ('Q') packet, marshalls its arguments, waits
95   // for a result, and finally reads and returns the result via an
96   // "out" parameter.
97
98   // The "invoker" template is used when receiving a remote procedure
99   // call.  This template function is suitable for use with the
100   // "callbacks" and "connection" classes.  It decodes incoming
101   // arguments, passes them to the wrapped function, and finally
102   // marshalls a reply packet.
103
104   template<typename R, typename... Arg>
105   status
106   call (connection *conn, const char *method, R *result, Arg... args)
107   {
108     if (!conn->send ('Q'))
109       return FAIL;
110     if (!marshall (conn, method))
111       return FAIL;
112     if (!marshall (conn, (int) sizeof... (Arg)))
113       return FAIL;
114     if (!marshall (conn, args...))
115       return FAIL;
116     if (!conn->wait_for_result ())
117       return FAIL;
118     if (!unmarshall (conn, result))
119       return FAIL;
120     return OK;
121   }
122
123   // The base case -- just return OK.
124   template<int I, typename... T>
125   typename std::enable_if<I == sizeof... (T), status>::type
126   unmarshall (connection *, std::tuple<T...> &)
127   {
128     return OK;
129   }
130
131   // Unmarshall this argument, then unmarshall all subsequent args.
132   template<int I, typename... T>
133   typename std::enable_if<I < sizeof... (T), status>::type
134   unmarshall (connection *conn, std::tuple<T...> &value)
135   {
136     if (!std::get<I> (value).unmarshall (conn))
137       return FAIL;
138     return unmarshall<I + 1, T...> (conn, value);
139   }
140
141   // Wrap a static function that is suitable for use as a callback.
142   // This is a template function inside a template class to work
143   // around limitations with multiple variadic packs.
144   template<typename R, typename... Arg>
145   class invoker
146   {
147     // Base case -- we can call the function.
148     template<int I, R func (connection *, Arg...), typename... T>
149     static typename std::enable_if<I == sizeof... (Arg), R>::type
150     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &,
151           T... args)
152     {
153       return func (conn, args...);
154     }
155
156     // Unpack one argument and continue the recursion.
157     template<int I, R func (connection *, Arg...), typename... T>
158     static typename std::enable_if<I < sizeof... (Arg), R>::type
159     call (connection *conn, const std::tuple<argument_wrapper<Arg>...> &value,
160           T... args)
161     {
162       return call<I + 1, func> (conn, value, args...,
163                                 std::get<I> (value).get ());
164     }
165
166   public:
167
168     // A callback function that reads arguments from the connection,
169     // calls the wrapped function, and then sends the result back on
170     // the connection.
171     template<R func (connection *, Arg...)>
172     static status
173     invoke (connection *conn)
174     {
175       if (!unmarshall_check (conn, sizeof... (Arg)))
176         return FAIL;
177       std::tuple<argument_wrapper<Arg>...> wrapped;
178       if (!unmarshall<0> (conn, wrapped))
179         return FAIL;
180
181       R result = call<0, func> (conn, wrapped);
182
183       if (!conn->send ('R'))
184         return FAIL;
185       return marshall (conn, result);
186     }
187   };
188 };
189
190 #endif // CC1_PLUGIN_RPC_HH