blob: 7f8e17684d945dfc67f91477e38f802facc1014b [file] [log] [blame]
//
// Copyright 2013 Francisco Jerez
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#ifndef CLOVER_CORE_PROPERTY_HPP
#define CLOVER_CORE_PROPERTY_HPP
#include <map>
#include "util/range.hpp"
#include "util/algorithm.hpp"
namespace clover {
class property_buffer;
namespace detail {
template<typename T>
class property_scalar {
public:
property_scalar(property_buffer &buf) : buf(buf) {
}
inline property_scalar &
operator=(const T &x);
private:
property_buffer &buf;
};
template<typename T>
class property_vector {
public:
property_vector(property_buffer &buf) : buf(buf) {
}
template<typename S>
inline property_vector &
operator=(const S &v);
private:
property_buffer &buf;
};
template<typename T>
class property_matrix {
public:
property_matrix(property_buffer &buf) : buf(buf) {
}
template<typename S>
inline property_matrix &
operator=(const S &v);
private:
property_buffer &buf;
};
class property_string {
public:
property_string(property_buffer &buf) : buf(buf) {
}
inline property_string &
operator=(const std::string &v);
private:
property_buffer &buf;
};
};
///
/// Return value buffer used by the CL property query functions.
///
class property_buffer {
public:
property_buffer(void *r_buf, size_t size, size_t *r_size) :
r_buf(r_buf), size(size), r_size(r_size) {
}
template<typename T>
detail::property_scalar<T>
as_scalar() {
return { *this };
}
template<typename T>
detail::property_vector<T>
as_vector() {
return { *this };
}
template<typename T>
detail::property_matrix<T>
as_matrix() {
return { *this };
}
detail::property_string
as_string() {
return { *this };
}
template<typename T>
iterator_range<T *>
allocate(size_t n) {
if (r_buf && size < n * sizeof(T))
throw error(CL_INVALID_VALUE);
if (r_size)
*r_size = n * sizeof(T);
if (r_buf)
return range((T *)r_buf, n);
else
return { };
}
private:
void *const r_buf;
const size_t size;
size_t *const r_size;
};
namespace detail {
template<typename T>
inline property_scalar<T> &
property_scalar<T>::operator=(const T &x) {
auto r = buf.allocate<T>(1);
if (!r.empty())
r.front() = x;
return *this;
}
template<typename T>
template<typename S>
inline property_vector<T> &
property_vector<T>::operator=(const S &v) {
auto r = buf.allocate<T>(v.size());
if (!r.empty())
copy(v, r.begin());
return *this;
}
template<typename T>
template<typename S>
inline property_matrix<T> &
property_matrix<T>::operator=(const S &v) {
auto r = buf.allocate<T *>(v.size());
if (!r.empty())
for_each([](typename S::value_type src, T *dst) {
if (dst)
copy(src, dst);
}, v, r);
return *this;
}
inline property_string &
property_string::operator=(const std::string &v) {
auto r = buf.allocate<char>(v.size() + 1);
if (!r.empty())
copy(range(v.begin(), r.size()), r.begin());
return *this;
}
};
template<typename T>
class property_element {
public:
property_element() : x() {
}
property_element(T x) : x(x) {
}
template<typename S>
S
as() const {
assert(sizeof(S) <= sizeof(T));
return reinterpret_cast<S>(x);
}
private:
T x;
};
template<typename D>
using property_list = std::map<D, property_element<D>>;
struct property_list_tag;
///
/// Create a clover::property_list object from a zero-terminated
/// CL property list.
///
template<typename T, typename D,
typename = typename std::enable_if<
std::is_same<T, property_list_tag>::value>::type>
property_list<D>
obj(const D *d_props) {
property_list<D> props;
while (d_props && *d_props) {
auto key = *d_props++;
auto value = *d_props++;
if (props.count(key))
throw error(CL_INVALID_PROPERTY);
props.insert({ key, value });
}
return props;
}
///
/// Create a zero-terminated CL property list from a
/// clover::property_list object.
///
template<typename D>
std::vector<D>
desc(const property_list<D> &props) {
std::vector<D> d_props;
for (auto &prop : props) {
d_props.push_back(prop.first);
d_props.push_back(prop.second.template as<D>());
}
d_props.push_back(0);
return d_props;
}
}
#endif