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