• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2013 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 
23 #ifndef CLOVER_CORE_PROPERTY_HPP
24 #define CLOVER_CORE_PROPERTY_HPP
25 
26 #include <map>
27 
28 #include "util/range.hpp"
29 #include "util/algorithm.hpp"
30 
31 namespace clover {
32    class property_buffer;
33 
34    namespace detail {
35       template<typename T>
36       class property_scalar {
37       public:
property_scalar(property_buffer & buf)38          property_scalar(property_buffer &buf) : buf(buf) {
39          }
40 
41          inline property_scalar &
42          operator=(const T &x);
43 
44       private:
45          property_buffer &buf;
46       };
47 
48       template<typename T>
49       class property_vector {
50       public:
property_vector(property_buffer & buf)51          property_vector(property_buffer &buf) : buf(buf) {
52          }
53 
54          template<typename S>
55          inline property_vector &
56          operator=(const S &v);
57 
58       private:
59          property_buffer &buf;
60       };
61 
62       template<typename T>
63       class property_matrix {
64       public:
property_matrix(property_buffer & buf)65          property_matrix(property_buffer &buf) : buf(buf) {
66          }
67 
68          template<typename S>
69          inline property_matrix &
70          operator=(const S &v);
71 
72       private:
73          property_buffer &buf;
74       };
75 
76       class property_string {
77       public:
property_string(property_buffer & buf)78          property_string(property_buffer &buf) : buf(buf) {
79          }
80 
81          inline property_string &
82          operator=(const std::string &v);
83 
84       private:
85          property_buffer &buf;
86       };
87    };
88 
89    ///
90    /// Return value buffer used by the CL property query functions.
91    ///
92    class property_buffer {
93    public:
property_buffer(void * r_buf,size_t size,size_t * r_size)94       property_buffer(void *r_buf, size_t size, size_t *r_size) :
95          r_buf(r_buf), size(size), r_size(r_size) {
96       }
97 
98       template<typename T>
99       detail::property_scalar<T>
as_scalar()100       as_scalar() {
101          return { *this };
102       }
103 
104       template<typename T>
105       detail::property_vector<T>
as_vector()106       as_vector() {
107          return { *this };
108       }
109 
110       template<typename T>
111       detail::property_matrix<T>
as_matrix()112       as_matrix() {
113          return { *this };
114       }
115 
116       detail::property_string
as_string()117       as_string() {
118          return { *this };
119       }
120 
121       template<typename T>
122       iterator_range<T *>
allocate(size_t n)123       allocate(size_t n) {
124          if (r_buf && size < n * sizeof(T))
125             throw error(CL_INVALID_VALUE);
126 
127          if (r_size)
128             *r_size = n * sizeof(T);
129 
130          if (r_buf)
131             return range((T *)r_buf, n);
132          else
133             return { };
134       }
135 
136    private:
137       void *const r_buf;
138       const size_t size;
139       size_t *const r_size;
140    };
141 
142    namespace detail {
143       template<typename T>
144       inline property_scalar<T> &
operator =(const T & x)145       property_scalar<T>::operator=(const T &x) {
146          auto r = buf.allocate<T>(1);
147 
148          if (!r.empty())
149             r.front() = x;
150 
151          return *this;
152       }
153 
154       template<typename T>
155       template<typename S>
156       inline property_vector<T> &
operator =(const S & v)157       property_vector<T>::operator=(const S &v) {
158          auto r = buf.allocate<T>(v.size());
159 
160          if (!r.empty())
161             copy(v, r.begin());
162 
163          return *this;
164       }
165 
166       template<typename T>
167       template<typename S>
168       inline property_matrix<T> &
operator =(const S & v)169       property_matrix<T>::operator=(const S &v) {
170          auto r = buf.allocate<T *>(v.size());
171 
172          if (!r.empty())
173             for_each([](typename S::value_type src, T *dst) {
174                   if (dst)
175                      copy(src, dst);
176                }, v, r);
177 
178          return *this;
179       }
180 
181       inline property_string &
operator =(const std::string & v)182       property_string::operator=(const std::string &v) {
183          auto r = buf.allocate<char>(v.size() + 1);
184 
185          if (!r.empty())
186             copy(range(v.begin(), r.size()), r.begin());
187 
188          return *this;
189       }
190    };
191 
192    template<typename T>
193    class property_element {
194    public:
property_element()195       property_element() : x() {
196       }
197 
property_element(T x)198       property_element(T x) : x(x) {
199       }
200 
201       template<typename S>
202       typename std::enable_if<!std::is_convertible<T, S>::value, S>::type
as() const203       as() const {
204          static_assert(sizeof(S) <= sizeof(T), "Ensure type fits in property list");
205          return reinterpret_cast<S>(x);
206       }
207 
208       template<typename S>
209       typename std::enable_if<std::is_convertible<T, S>::value, S>::type
as() const210       as() const {
211          return static_cast<S>(x);
212       }
213 
214    private:
215       T x;
216    };
217 
218    template<typename D>
219    using property_list = std::map<D, property_element<D>>;
220 
221    struct property_list_tag;
222 
223    ///
224    /// Create a clover::property_list object from a zero-terminated
225    /// CL property list.
226    ///
227    template<typename T, typename D,
228             typename = typename std::enable_if<
229                std::is_same<T, property_list_tag>::value>::type>
230    property_list<D>
obj(const D * d_props)231    obj(const D *d_props) {
232       property_list<D> props;
233 
234       while (d_props && *d_props) {
235          auto key = *d_props++;
236          auto value = *d_props++;
237 
238          if (props.count(key))
239             throw error(CL_INVALID_PROPERTY);
240 
241          props.insert({ key, value });
242       }
243 
244       return props;
245    }
246 
247    ///
248    /// Create a zero-terminated CL property list from a
249    /// clover::property_list object.
250    ///
251    template<typename D>
252    std::vector<D>
desc(const property_list<D> & props)253    desc(const property_list<D> &props) {
254       std::vector<D> d_props;
255 
256       for (auto &prop : props) {
257          d_props.push_back(prop.first);
258          d_props.push_back(prop.second.template as<D>());
259       }
260 
261       d_props.push_back(0);
262 
263       return d_props;
264    }
265 }
266 
267 #endif
268