clover: Import new utility library.

Tested-by: Tom Stellard <thomas.stellard@amd.com>
This commit is contained in:
Francisco Jerez 2013-10-06 13:47:19 -07:00
parent 7baad4b996
commit e93efa0d50
12 changed files with 2157 additions and 1 deletions

View file

@ -610,7 +610,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = api/ core/
INPUT = api/ core/ util/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

View file

@ -1,4 +1,14 @@
CPP_SOURCES := \
util/adaptor.hpp \
util/algebra.hpp \
util/algorithm.hpp \
util/compat.cpp \
util/compat.hpp \
util/functional.hpp \
util/lazy.hpp \
util/pointer.hpp \
util/range.hpp \
util/tuple.hpp \
core/base.hpp \
core/compat.hpp \
core/compiler.hpp \

View file

@ -0,0 +1,183 @@
//
// 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_UTIL_ADAPTOR_HPP
#define CLOVER_UTIL_ADAPTOR_HPP
#include <iterator>
#include "util/tuple.hpp"
#include "util/pointer.hpp"
#include "util/functional.hpp"
namespace clover {
namespace detail {
///
/// Implementation of the iterator concept that transforms the
/// value of the source iterators \a Is on dereference by use of
/// a functor \a F.
///
/// The exact category of the resulting iterator should be the
/// least common denominator of the source iterator categories.
///
template<typename F, typename... Is>
class iterator_adaptor {
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename std::result_of<
F(typename std::iterator_traits<Is>::reference...)
>::type reference;
typedef typename std::remove_reference<reference>::type value_type;
typedef pseudo_ptr<value_type> pointer;
typedef std::ptrdiff_t difference_type;
iterator_adaptor() {
}
iterator_adaptor(F f, std::tuple<Is...> &&its) :
f(f), its(std::move(its)) {
}
reference
operator*() const {
return tuple::apply(f, tuple::map(derefs(), its));
}
iterator_adaptor &
operator++() {
tuple::map(preincs(), its);
return *this;
}
iterator_adaptor
operator++(int) {
auto jt = *this;
++*this;
return jt;
}
bool
operator==(const iterator_adaptor &jt) const {
return its == jt.its;
}
bool
operator!=(const iterator_adaptor &jt) const {
return its != jt.its;
}
pointer
operator->() const {
return { **this };
}
iterator_adaptor &
operator--() {
tuple::map(predecs(), its);
return *this;
}
iterator_adaptor
operator--(int) {
auto jt = *this;
--*this;
return jt;
}
iterator_adaptor &
operator+=(difference_type n) {
tuple::map(advances_by(n), its);
return *this;
}
iterator_adaptor &
operator-=(difference_type n) {
tuple::map(advances_by(n), its);
return *this;
}
iterator_adaptor
operator+(difference_type n) const {
auto jt = *this;
jt += n;
return jt;
}
iterator_adaptor
operator-(difference_type n) const {
auto jt = *this;
jt -= n;
return jt;
}
difference_type
operator-(const iterator_adaptor &jt) const {
return std::get<0>(its) - std::get<0>(jt.its);
}
reference
operator[](difference_type n) const {
return *(*this + n);
}
bool
operator<(iterator_adaptor &jt) const {
return *this - jt < 0;
}
bool
operator>(iterator_adaptor &jt) const {
return *this - jt > 0;
}
bool
operator>=(iterator_adaptor &jt) const {
return !(*this < jt);
}
bool
operator<=(iterator_adaptor &jt) const {
return !(*this > jt);
}
protected:
F f;
std::tuple<Is...> its;
};
template<typename F, typename... Is>
iterator_adaptor<F, Is...>
operator+(typename iterator_adaptor<F, Is...>::difference_type n,
const iterator_adaptor<F, Is...> &jt) {
return (jt + n);
}
template<typename F, typename... Is>
iterator_adaptor<F, Is...>
operator-(typename iterator_adaptor<F, Is...>::difference_type n,
const iterator_adaptor<F, Is...> &jt) {
return (jt - n);
}
}
}
#endif

View file

@ -0,0 +1,160 @@
//
// 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_UTIL_ALGEBRA_HPP
#define CLOVER_UTIL_ALGEBRA_HPP
#include <type_traits>
#include "util/range.hpp"
#include "util/functional.hpp"
namespace clover {
///
/// Class that identifies vectors (in the linear-algebraic sense).
///
/// There should be a definition of this class for each type that
/// makes sense as vector arithmetic operand.
///
template<typename V, typename = void>
struct vector_traits;
///
/// References of vectors are vectors.
///
template<typename T>
struct vector_traits<T &, typename vector_traits<T>::enable> {
typedef void enable;
};
///
/// Constant vectors are vectors.
///
template<typename T>
struct vector_traits<const T, typename vector_traits<T>::enable> {
typedef void enable;
};
///
/// Arrays of arithmetic types are vectors.
///
template<typename T, std::size_t N>
struct vector_traits<std::array<T, N>,
typename std::enable_if<
std::is_arithmetic<T>::value>::type> {
typedef void enable;
};
namespace detail {
template<typename... Ts>
struct are_defined {
typedef void enable;
};
}
///
/// The result of mapping a vector is a vector.
///
template<typename F, typename... Vs>
struct vector_traits<adaptor_range<F, Vs...>,
typename detail::are_defined<
typename vector_traits<Vs>::enable...>::enable> {
typedef void enable;
};
///
/// Vector sum.
///
template<typename U, typename V,
typename = typename vector_traits<U>::enable,
typename = typename vector_traits<V>::enable>
adaptor_range<plus, U, V>
operator+(U &&u, V &&v) {
return map(plus(), std::forward<U>(u), std::forward<V>(v));
}
///
/// Vector difference.
///
template<typename U, typename V,
typename = typename vector_traits<U>::enable,
typename = typename vector_traits<V>::enable>
adaptor_range<minus, U, V>
operator-(U &&u, V &&v) {
return map(minus(), std::forward<U>(u), std::forward<V>(v));
}
///
/// Scalar multiplication.
///
template<typename U, typename T,
typename = typename vector_traits<U>::enable>
adaptor_range<multiplies_by_t<T>, U>
operator*(U &&u, T &&a) {
return map(multiplies_by<T>(std::forward<T>(a)), std::forward<U>(u));
}
///
/// Scalar multiplication.
///
template<typename U, typename T,
typename = typename vector_traits<U>::enable>
adaptor_range<multiplies_by_t<T>, U>
operator*(T &&a, U &&u) {
return map(multiplies_by<T>(std::forward<T>(a)), std::forward<U>(u));
}
///
/// Additive inverse.
///
template<typename U,
typename = typename vector_traits<U>::enable>
adaptor_range<negate, U>
operator-(U &&u) {
return map(negate(), std::forward<U>(u));
}
namespace detail {
template<typename U, typename V>
using dot_type = typename std::common_type<
typename std::remove_reference<U>::type::value_type,
typename std::remove_reference<V>::type::value_type
>::type;
}
///
/// Dot product of two vectors.
///
/// It can also do matrix multiplication if \a u or \a v is a
/// vector of vectors.
///
template<typename U, typename V,
typename = typename vector_traits<U>::enable,
typename = typename vector_traits<V>::enable>
detail::dot_type<U, V>
dot(U &&u, V &&v) {
return fold(plus(), detail::dot_type<U, V>(),
map(multiplies(), u, v));
}
}
#endif

View file

@ -0,0 +1,206 @@
//
// 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_UTIL_ALGORITHM_HPP
#define CLOVER_UTIL_ALGORITHM_HPP
#include <algorithm>
#include <stdexcept>
#include "util/range.hpp"
#include "util/functional.hpp"
namespace clover {
namespace detail {
template<typename R>
using preferred_reference_type = decltype(*std::declval<R>().begin());
}
///
/// Return the first element in a range.
///
template<typename R>
detail::preferred_reference_type<R>
head(R &&r) {
assert(!r.empty());
return r.front();
}
///
/// Return all elements in a range but the first.
///
template<typename R>
slice_range<R>
tail(R &&r) {
assert(!r.empty());
return { std::forward<R>(r), 1, r.size() };
}
///
/// Combine a variable number of ranges element-wise in a single
/// range of tuples.
///
template<typename... Rs>
adaptor_range<zips, Rs...>
zip(Rs &&... rs) {
return map(zips(), std::forward<Rs>(rs)...);
}
///
/// Evaluate the elements of a range.
///
/// Useful because most of the range algorithms evaluate their
/// result lazily.
///
template<typename R>
void
eval(R &&r) {
for (auto i = r.begin(), e = r.end(); i != e; ++i)
*i;
}
///
/// Apply functor \a f element-wise on a variable number of ranges
/// \a rs.
///
/// The functor \a f should take as many arguments as ranges are
/// provided.
///
template<typename F, typename... Rs>
void
for_each(F &&f, Rs &&... rs) {
eval(map(std::forward<F>(f), std::forward<Rs>(rs)...));
}
///
/// Copy all elements from range \a r into an output container
/// starting from iterator \a i.
///
template<typename R, typename I>
void
copy(R &&r, I i) {
for (detail::preferred_reference_type<R> x : r)
*(i++) = x;
}
///
/// Reduce the elements of range \a r by applying functor \a f
/// element by element.
///
/// \a f should take an accumulator value (which is initialized to
/// \a a) and an element value as arguments, and return an updated
/// accumulator value.
///
/// \returns The final value of the accumulator.
///
template<typename F, typename A, typename R>
A
fold(F &&f, A a, R &&r) {
for (detail::preferred_reference_type<R> x : r)
a = f(a, x);
return a;
}
///
/// Return how many elements of range \a r are equal to \a x.
///
template<typename T, typename R>
typename std::remove_reference<R>::type::size_type
count(T &&x, R &&r) {
typename std::remove_reference<R>::type::size_type n = 0;
for (detail::preferred_reference_type<R> y : r) {
if (x == y)
n++;
}
return n;
}
///
/// Return the first element in range \a r for which predicate \a f
/// evaluates to true.
///
template<typename F, typename R>
detail::preferred_reference_type<R>
find(F &&f, R &&r) {
for (detail::preferred_reference_type<R> x : r) {
if (f(x))
return x;
}
throw std::out_of_range("");
}
///
/// Return true if the element-wise application of predicate \a f
/// on \a rs evaluates to true for all elements.
///
template<typename F, typename... Rs>
bool
all_of(F &&f, Rs &&... rs) {
for (auto b : map(f, rs...)) {
if (!b)
return false;
}
return true;
}
///
/// Return true if the element-wise application of predicate \a f
/// on \a rs evaluates to true for any element.
///
template<typename F, typename... Rs>
bool
any_of(F &&f, Rs &&... rs) {
for (auto b : map(f, rs...)) {
if (b)
return true;
}
return false;
}
///
/// Erase elements for which predicate \a f evaluates to true from
/// container \a r.
///
template<typename F, typename R>
void
erase_if(F &&f, R &&r) {
auto i = r.begin(), e = r.end();
for (auto j = r.begin(); j != e; ++j) {
if (!f(*j)) {
if (j != i)
*i = std::move(*j);
++i;
}
}
r.erase(i, e);
}
}
#endif

View file

@ -0,0 +1,38 @@
//
// 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.
//
#include "util/compat.hpp"
using namespace clover::compat;
exception::~exception() {
}
const char *
exception::what() const {
return "";
}
const char *
runtime_error::what() const {
return _what.c_str();
}

View file

@ -0,0 +1,328 @@
//
// Copyright 2012 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_UTIL_COMPAT_HPP
#define CLOVER_UTIL_COMPAT_HPP
#include <new>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stdint.h>
namespace clover {
namespace compat {
// XXX - For cases where we can't rely on STL... I.e. the
// interface between code compiled as C++98 and C++11
// source. Get rid of this as soon as everything can be
// compiled as C++11.
template<typename T>
class vector {
protected:
static T *
alloc(int n, const T *q, int m) {
T *p = reinterpret_cast<T *>(std::malloc(n * sizeof(T)));
for (int i = 0; i < m; ++i)
new(&p[i]) T(q[i]);
return p;
}
static void
free(int n, T *p) {
for (int i = 0; i < n; ++i)
p[i].~T();
std::free(p);
}
public:
typedef T *iterator;
typedef const T *const_iterator;
typedef T value_type;
typedef T &reference;
typedef const T &const_reference;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
vector() : p(NULL), n(0) {
}
vector(const vector &v) : p(alloc(v.n, v.p, v.n)), n(v.n) {
}
vector(iterator p, size_type n) : p(alloc(n, p, n)), n(n) {
}
template<typename C>
vector(const C &v) :
p(alloc(v.size(), &*v.begin(), v.size())), n(v.size()) {
}
~vector() {
free(n, p);
}
vector &
operator=(const vector &v) {
free(n, p);
p = alloc(v.n, v.p, v.n);
n = v.n;
return *this;
}
void
reserve(size_type m) {
if (n < m) {
T *q = alloc(m, p, n);
free(n, p);
p = q;
n = m;
}
}
void
resize(size_type m, T x = T()) {
size_type n = size();
reserve(m);
for (size_type i = n; i < m; ++i)
new(&p[i]) T(x);
}
void
push_back(const T &x) {
size_type n = size();
reserve(n + 1);
new(&p[n]) T(x);
}
size_type
size() const {
return n;
}
iterator
begin() {
return p;
}
const_iterator
begin() const {
return p;
}
iterator
end() {
return p + n;
}
const_iterator
end() const {
return p + n;
}
reference
operator[](size_type i) {
return p[i];
}
const_reference
operator[](size_type i) const {
return p[i];
}
private:
iterator p;
size_type n;
};
template<typename T>
class vector_ref {
public:
typedef T *iterator;
typedef const T *const_iterator;
typedef T value_type;
typedef T &reference;
typedef const T &const_reference;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
vector_ref(iterator p, size_type n) : p(p), n(n) {
}
template<typename C>
vector_ref(C &v) : p(&*v.begin()), n(v.size()) {
}
size_type
size() const {
return n;
}
iterator
begin() {
return p;
}
const_iterator
begin() const {
return p;
}
iterator
end() {
return p + n;
}
const_iterator
end() const {
return p + n;
}
reference
operator[](int i) {
return p[i];
}
const_reference
operator[](int i) const {
return p[i];
}
private:
iterator p;
size_type n;
};
class istream {
public:
typedef vector_ref<const unsigned char> buffer_t;
class error {
public:
virtual ~error() {}
};
istream(const buffer_t &buf) : buf(buf), offset(0) {}
void
read(char *p, size_t n) {
if (offset + n > buf.size())
throw error();
std::memcpy(p, buf.begin() + offset, n);
offset += n;
}
private:
const buffer_t &buf;
size_t offset;
};
class ostream {
public:
typedef vector<unsigned char> buffer_t;
ostream(buffer_t &buf) : buf(buf), offset(buf.size()) {}
void
write(const char *p, size_t n) {
buf.resize(offset + n);
std::memcpy(buf.begin() + offset, p, n);
offset += n;
}
private:
buffer_t &buf;
size_t offset;
};
class string : public vector_ref<const char> {
public:
string(const char *p) : vector_ref(p, std::strlen(p)) {
}
template<typename C>
string(const C &v) : vector_ref(v) {
}
operator std::string() const {
return std::string(begin(), end());
}
const char *
c_str() const {
return begin();
}
const char *
find(const string &s) const {
for (size_t i = 0; i + s.size() < size(); ++i) {
if (!std::memcmp(begin() + i, s.begin(), s.size()))
return begin() + i;
}
return end();
}
};
template<typename T>
bool
operator==(const vector_ref<T> &a, const vector_ref<T> &b) {
if (a.size() != b.size())
return false;
for (size_t i = 0; i < a.size(); ++i)
if (a[i] != b[i])
return false;
return true;
}
class exception {
public:
exception() {}
virtual ~exception();
virtual const char *what() const;
};
class runtime_error : public exception {
public:
runtime_error(const string &what) : _what(what) {}
virtual const char *what() const;
protected:
string _what;
};
}
}
#endif

View file

@ -0,0 +1,375 @@
//
// 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_UTIL_FUNCTIONAL_HPP
#define CLOVER_UTIL_FUNCTIONAL_HPP
#include <type_traits>
namespace clover {
struct identity {
template<typename T>
typename std::remove_reference<T>::type
operator()(T &&x) const {
return x;
}
};
struct plus {
template<typename T, typename S>
typename std::common_type<T, S>::type
operator()(T x, S y) const {
return x + y;
}
};
struct minus {
template<typename T, typename S>
typename std::common_type<T, S>::type
operator()(T x, S y) const {
return x - y;
}
};
struct negate {
template<typename T>
T
operator()(T x) const {
return -x;
}
};
struct multiplies {
template<typename T, typename S>
typename std::common_type<T, S>::type
operator()(T x, S y) const {
return x * y;
}
};
struct divides {
template<typename T, typename S>
typename std::common_type<T, S>::type
operator()(T x, S y) const {
return x / y;
}
};
struct modulus {
template<typename T, typename S>
typename std::common_type<T, S>::type
operator()(T x, S y) const {
return x % y;
}
};
struct minimum {
template<typename T>
T
operator()(T x) const {
return x;
}
template<typename T, typename... Ts>
T
operator()(T x, Ts... xs) const {
T y = minimum()(xs...);
return x < y ? x : y;
}
};
struct maximum {
template<typename T>
T
operator()(T x) const {
return x;
}
template<typename T, typename... Ts>
T
operator()(T x, Ts... xs) const {
T y = maximum()(xs...);
return x < y ? y : x;
}
};
struct preincs {
template<typename T>
T &
operator()(T &x) const {
return ++x;
}
};
struct predecs {
template<typename T>
T &
operator()(T &x) const {
return --x;
}
};
template<typename T>
class multiplies_by_t {
public:
multiplies_by_t(T x) : x(x) {
}
template<typename S>
typename std::common_type<T, S>::type
operator()(S y) const {
return x * y;
}
private:
T x;
};
template<typename T>
multiplies_by_t<T>
multiplies_by(T x) {
return { x };
}
template<typename T>
class preincs_by_t {
public:
preincs_by_t(T n) : n(n) {
}
template<typename S>
S &
operator()(S &x) const {
return x += n;
}
private:
T n;
};
template<typename T>
preincs_by_t<T>
preincs_by(T n) {
return { n };
}
template<typename T>
class predecs_by_t {
public:
predecs_by_t(T n) : n(n) {
}
template<typename S>
S &
operator()(S &x) const {
return x -= n;
}
private:
T n;
};
template<typename T>
predecs_by_t<T>
predecs_by(T n) {
return { n };
}
struct greater {
template<typename T, typename S>
bool
operator()(T x, S y) const {
return x > y;
}
};
struct derefs {
template<typename T>
auto
operator()(T &&x) const -> decltype(*x) {
return *x;
}
};
struct addresses {
template<typename T>
T *
operator()(T &x) const {
return &x;
}
template<typename T>
T *
operator()(std::reference_wrapper<T> x) const {
return &x.get();
}
};
struct begins {
template<typename T>
auto
operator()(T &x) const -> decltype(x.begin()) {
return x.begin();
}
};
struct ends {
template<typename T>
auto
operator()(T &x) const -> decltype(x.end()) {
return x.end();
}
};
struct sizes {
template<typename T>
auto
operator()(T &x) const -> decltype(x.size()) {
return x.size();
}
};
template<typename T>
class advances_by_t {
public:
advances_by_t(T n) : n(n) {
}
template<typename S>
S
operator()(S &&it) const {
std::advance(it, n);
return it;
}
private:
T n;
};
template<typename T>
advances_by_t<T>
advances_by(T n) {
return { n };
}
struct zips {
template<typename... Ts>
std::tuple<Ts...>
operator()(Ts &&... xs) const {
return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}
};
struct is_zero {
template<typename T>
bool
operator()(const T &x) const {
return x == 0;
}
};
struct keys {
template<typename P>
typename std::remove_reference<P>::type::first_type &
operator()(P &&p) const {
return p.first;
}
};
struct values {
template<typename P>
typename std::remove_reference<P>::type::second_type &
operator()(P &&p) const {
return p.second;
}
};
class name_equals {
public:
name_equals(const std::string &name) : name(name) {
}
template<typename T>
bool
operator()(const T &x) const {
return std::string(x.name.begin(), x.name.end()) == name;
}
private:
const std::string &name;
};
template<typename T>
class key_equals_t {
public:
key_equals_t(T &&x) : x(x) {
}
template<typename S>
bool
operator()(const std::pair<T, S> &p) const {
return p.first == x;
}
private:
T x;
};
template<typename T>
key_equals_t<T>
key_equals(T &&x) {
return { std::forward<T>(x) };
}
template<typename T>
class type_equals_t {
public:
type_equals_t(T type) : type(type) {
}
template<typename S>
bool
operator()(const S &x) const {
return x.type == type;
}
private:
T type;
};
template<typename T>
type_equals_t<T>
type_equals(T x) {
return { x };
}
struct interval_overlaps {
template<typename T>
bool
operator()(T x0, T x1, T y0, T y1) {
return ((x0 <= y0 && y0 < x1) ||
(y0 <= x0 && x0 < y1));
}
};
}
#endif

View file

@ -0,0 +1,161 @@
//
// 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_UTIL_LAZY_HPP
#define CLOVER_UTIL_LAZY_HPP
#include <type_traits>
#include <stdexcept>
#include <memory>
namespace clover {
namespace detail {
template<typename T>
class basic_lazy {
public:
virtual
~basic_lazy() {
}
virtual basic_lazy *
clone() const = 0;
virtual
operator T() const = 0;
};
template<typename T, typename F>
class deferred_lazy : public basic_lazy<T> {
public:
template<typename G>
deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) {
}
virtual basic_lazy<T> *
clone() const {
return new deferred_lazy(*this);
}
operator T() const {
if (f) {
x = (*f)();
f = {};
}
return x;
}
private:
mutable std::shared_ptr<F> f;
mutable T x;
};
template<typename T>
class strict_lazy : public basic_lazy<T> {
public:
template<typename S>
strict_lazy(S &&x) : x(std::forward<S>(x)) {
}
virtual basic_lazy<T> *
clone() const {
return new strict_lazy(*this);
}
operator T() const {
return x;
}
private:
T x;
};
}
///
/// Object that represents a value of type \a T that is calculated
/// lazily as soon as it is required.
///
template<typename T>
class lazy {
public:
class undefined_error : std::logic_error {
public:
undefined_error() : std::logic_error("") {
}
};
///
/// Initialize to some fixed value \a x which isn't calculated
/// lazily.
///
lazy(T x) : obj(new detail::strict_lazy<T>(x)) {
}
///
/// Initialize by providing a functor \a f that will calculate
/// the value on-demand.
///
template<typename F>
lazy(F &&f) : obj(new detail::deferred_lazy<
T, typename std::remove_reference<F>::type
>(std::forward<F>(f))) {
}
///
/// Initialize to undefined.
///
lazy() : lazy([]() {
throw undefined_error();
return T();
}) {
}
lazy(const lazy &other) : obj(obj->clone()) {
}
lazy(lazy &&other) : obj(NULL) {
std::swap(obj, other.obj);
}
~lazy() {
delete obj;
}
lazy &
operator=(lazy other) {
std::swap(obj, other.obj);
return *this;
}
///
/// Evaluate the value.
///
operator T() const {
return *obj;
}
private:
detail::basic_lazy<T> *obj;
};
}
#endif

View file

@ -0,0 +1,157 @@
//
// 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_UTIL_POINTER_HPP
#define CLOVER_UTIL_POINTER_HPP
#include <atomic>
namespace clover {
///
/// Base class for objects that support reference counting.
///
class ref_counter {
public:
ref_counter() : _ref_count(1) {}
unsigned
ref_count() {
return _ref_count;
}
void
retain() {
_ref_count++;
}
bool
release() {
return (--_ref_count) == 0;
}
private:
std::atomic<unsigned> _ref_count;
};
///
/// Intrusive smart pointer for objects that implement the
/// clover::ref_counter interface.
///
template<typename T>
class ref_ptr {
public:
ref_ptr(T *q = NULL) : p(NULL) {
reset(q);
}
ref_ptr(const ref_ptr<T> &ref) : p(NULL) {
reset(ref.p);
}
~ref_ptr() {
reset(NULL);
}
void
reset(T *q = NULL) {
if (q)
q->retain();
if (p && p->release())
delete p;
p = q;
}
ref_ptr &
operator=(const ref_ptr &ref) {
reset(ref.p);
return *this;
}
T &
operator*() const {
return *p;
}
T *
operator->() const {
return p;
}
explicit operator bool() const {
return p;
}
private:
T *p;
};
///
/// Transfer the caller's ownership of a reference-counted object
/// to a clover::ref_ptr smart pointer.
///
template<typename T>
inline ref_ptr<T>
transfer(T *p) {
ref_ptr<T> ref { p };
p->release();
return ref;
}
///
/// Class that implements the usual pointer interface but in fact
/// contains the object it seems to be pointing to.
///
template<typename T>
class pseudo_ptr {
public:
pseudo_ptr(T x) : x(x) {
}
pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
}
pseudo_ptr &
operator=(const pseudo_ptr &p) {
x = p.x;
return *this;
}
T &
operator*() {
return x;
}
T *
operator->() {
return &x;
}
explicit operator bool() const {
return true;
}
private:
T x;
};
}
#endif

View file

@ -0,0 +1,421 @@
//
// 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_UTIL_RANGE_HPP
#define CLOVER_UTIL_RANGE_HPP
#include <array>
#include <vector>
#include "util/adaptor.hpp"
namespace clover {
///
/// Class that identifies container types where the elements of a
/// range can be stored by the type conversion operator.
///
/// \a T identifies the range element type.
///
template<typename T, typename V>
struct range_store_traits;
template<typename T>
struct range_store_traits<T, std::vector<T>> {
typedef void enable;
template<typename R>
static std::vector<T>
create(const R &r) {
return { r.begin(), r.end() };
}
};
template<typename T, std::size_t N>
struct range_store_traits<T, std::array<T, N>> {
typedef void enable;
template<typename R>
static std::array<T, N>
create(const R &r) {
std::array<T, N> v;
assert(r.size() == v.size());
copy(r, v.begin());
return v;
}
};
namespace detail {
///
/// Common functionality that is shared by other implementations
/// of the container concept.
///
template<typename R, typename I, typename CI>
class basic_range {
public:
typedef I iterator;
typedef CI const_iterator;
typedef typename std::iterator_traits<iterator>::value_type value_type;
typedef typename std::iterator_traits<iterator>::reference
reference;
typedef typename std::iterator_traits<const_iterator>::reference
const_reference;
typedef typename std::iterator_traits<iterator>::difference_type
difference_type;
typedef std::size_t size_type;
bool
operator==(const basic_range &r) const {
return *static_cast<const R *>(this) == r;
}
bool
operator!=(const basic_range &r) const {
return !(*this == r);
}
iterator
begin() {
return static_cast<R *>(this)->begin();
}
iterator
end() {
return static_cast<R *>(this)->end();
}
const_iterator
begin() const {
return static_cast<const R *>(this)->begin();
}
const_iterator
end() const {
return static_cast<const R *>(this)->end();
}
std::reverse_iterator<iterator>
rbegin() {
return { begin() };
}
std::reverse_iterator<iterator>
rend() {
return { end() };
}
reference
front() {
return *begin();
}
reference
back() {
return *(end() - 1);
}
bool
empty() const {
return begin() == end();
}
reference
at(size_type i) {
if (i >= static_cast<const R *>(this)->size())
throw std::out_of_range("");
return begin()[i];
}
const_reference
at(size_type i) const {
if (i >= static_cast<const R *>(this)->size())
throw std::out_of_range("");
return begin()[i];
}
reference
operator[](size_type i) {
return begin()[i];
}
const_reference
operator[](size_type i) const {
return begin()[i];
}
template<typename V>
using store_traits = range_store_traits<
typename std::remove_cv<value_type>::type, V
>;
template<typename V,
typename = typename store_traits<V>::enable>
operator V() const {
return store_traits<V>::create(*static_cast<const R *>(this));
}
};
}
///
/// Range that contains all elements delimited by an iterator pair
/// (\a i, \a j). Use range() as convenience constructor.
///
template<typename I>
class iterator_range : public detail::basic_range<iterator_range<I>, I, I> {
public:
typedef detail::basic_range<iterator_range<I>, I, I> super;
iterator_range() : i(), j() {
}
iterator_range(I i, I j) : i(i), j(j) {
}
bool
operator==(const iterator_range &r) const {
return i == r.i && j == r.j;
}
I
begin() const {
return i;
}
I
end() const {
return j;
}
typename super::size_type
size() const {
return end() - begin();
}
private:
I i, j;
};
namespace detail {
template<typename T>
using preferred_iterator_type = decltype(std::declval<T>().begin());
template<typename F, typename... Os>
using adaptor_iterator = detail::iterator_adaptor<
F, preferred_iterator_type<Os>...>;
template<typename F, typename... Os>
using adaptor_const_iterator = detail::iterator_adaptor<
F, preferred_iterator_type<const Os>...>;
}
///
/// Range that transforms the contents of a number of source ranges
/// \a os element-wise by using the provided functor \a f. Use
/// map() as convenience constructor.
///
template<typename F, typename... Os>
class adaptor_range :
public detail::basic_range<adaptor_range<F, Os...>,
detail::adaptor_iterator<F, Os...>,
detail::adaptor_const_iterator<F, Os...>> {
public:
typedef detail::basic_range<adaptor_range<F, Os...>,
detail::adaptor_iterator<F, Os...>,
detail::adaptor_const_iterator<F, Os...>
> super;
template<typename G, typename... Rs>
adaptor_range(G &&f, Rs &&... os) :
f(std::forward<G>(f)), os(std::forward<Rs>(os)...) {
}
bool
operator==(const adaptor_range &r) const {
return f == r.f && os == r.os;
}
detail::adaptor_iterator<F, Os...>
begin() {
return { f, tuple::map(begins(), os) };
}
detail::adaptor_iterator<F, Os...>
end() {
return { f, tuple::map(advances_by(size()),
tuple::map(begins(), os)) };
}
detail::adaptor_const_iterator<F, Os...>
begin() const {
return { f, tuple::map(begins(), os) };
}
detail::adaptor_const_iterator<F, Os...>
end() const {
return { f, tuple::map(ends(), os) };
}
typename super::size_type
size() const {
return tuple::apply(minimum(), tuple::map(sizes(), os));
}
private:
F f;
std::tuple<Os...> os;
};
///
/// Range that contains all elements delimited by the index pair
/// (\a i, \a j) in the source range \a r. Use slice() as
/// convenience constructor.
///
template<typename O>
class slice_range :
public detail::basic_range<slice_range<O>,
detail::preferred_iterator_type<O>,
detail::preferred_iterator_type<const O>> {
public:
typedef detail::basic_range<slice_range<O>,
detail::preferred_iterator_type<O>,
detail::preferred_iterator_type<const O>
> super;
template<typename R>
slice_range(R &&r, typename super::size_type i,
typename super::size_type j) :
o(std::forward<R>(r)), i(i), j(j) {
}
bool
operator==(const slice_range &r) const {
return o == r.o && i == r.i && j == r.j;
}
typename super::iterator
begin() {
return std::next(o.begin(), i);
}
typename super::iterator
end() {
return std::next(o.begin(), j);
}
typename super::const_iterator
begin() const {
return std::next(o.begin(), i);
}
typename super::const_iterator
end() const {
return std::next(o.begin(), j);
}
typename super::size_type
size() const {
return j - i;
}
private:
O o;
typename super::size_type i, j;
};
///
/// Create a range from an iterator pair (\a i, \a j).
///
/// \sa iterator_range.
///
template<typename T>
iterator_range<T>
range(T i, T j) {
return { i, j };
}
///
/// Create a range of \a n elements starting from iterator \a i.
///
/// \sa iterator_range.
///
template<typename T>
iterator_range<T>
range(T i, typename std::iterator_traits<T>::difference_type n) {
return { i, i + n };
}
///
/// Create a range by transforming the contents of a number of
/// source ranges \a rs element-wise using a provided functor \a f.
///
/// \sa adaptor_range.
///
template<typename F, typename... Rs>
adaptor_range<F, Rs...>
map(F &&f, Rs &&... rs) {
return { std::forward<F>(f), std::forward<Rs>(rs)... };
}
///
/// Create a range identical to another range \a r.
///
template<typename R>
adaptor_range<identity, R>
range(R &&r) {
return { identity(), std::forward<R>(r) };
}
///
/// Create a range by taking the elements delimited by the index
/// pair (\a i, \a j) in a source range \a r.
///
/// \sa slice_range.
///
template<typename R>
slice_range<R>
slice(R &&r, typename slice_range<R>::size_type i,
typename slice_range<R>::size_type j) {
return { std::forward<R>(r), i, j };
}
///
/// Range that behaves as a vector of references of type \a T.
///
/// Useful because STL containers cannot contain references to
/// objects as elements.
///
template<typename T>
class ref_vector : public adaptor_range<derefs, std::vector<T *>> {
public:
ref_vector(std::initializer_list<std::reference_wrapper<T>> il) :
adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) {
}
template<typename R>
ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>(
derefs(), map(addresses(), std::forward<R>(r))) {
}
};
}
#endif

View file

@ -0,0 +1,117 @@
//
// 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_UTIL_TUPLE_HPP
#define CLOVER_UTIL_TUPLE_HPP
#include <tuple>
namespace clover {
namespace tuple {
///
/// Static sequence of integers.
///
template<int... Is>
struct integral_sequence;
///
/// Static sequence containing all integers from 0 to N-1.
///
template<int N, int... Is>
struct enumerate {
typedef typename enumerate<N-1, N-1, Is...>::type
type;
};
template<int... Is>
struct enumerate<0, Is...> {
typedef integral_sequence<Is...> type;
};
namespace detail {
template<typename F, typename T,
typename E = typename enumerate<std::tuple_size<
typename std::remove_reference<T>::type>::value
>::type>
struct _apply;
template<typename F, typename T, int... Is>
struct _apply<F, T, integral_sequence<Is...>> {
typedef typename std::remove_reference<F>::type func_type;
typedef decltype(
std::declval<func_type>()(std::get<Is>(std::declval<T &&>())...)
) value_type;
static value_type
eval(F &&f, T &&t) {
return f(std::get<Is>(std::forward<T>(t))...);
}
};
}
///
/// Evaluate function \a f with the elements of tuple \a t
/// expanded as arguments.
///
template<typename F, typename T>
typename detail::_apply<F, T>::value_type
apply(F &&f, T &&t) {
return detail::_apply<F, T>::eval(std::forward<F>(f),
std::forward<T>(t));
}
namespace detail {
template<typename F, typename T,
typename E = typename enumerate<std::tuple_size<
typename std::remove_reference<T>::type>::value
>::type>
struct _map;
template<typename F, typename T, int... Is>
struct _map<F, T, integral_sequence<Is...>> {
typedef typename std::remove_reference<F>::type func_type;
typedef std::tuple<
decltype(std::declval<func_type>()(
std::get<Is>(std::declval<T &&>())))...
> value_type;
static value_type
eval(F &&f, T &&t) {
return value_type(f(std::get<Is>(std::forward<T>(t)))...);
}
};
}
///
/// Evaluate function \a f on each element of the tuple \a t and
/// return the resulting values as a new tuple.
///
template<typename F, typename T>
typename detail::_map<F, T>::value_type
map(F &&f, T &&t) {
return detail::_map<F, T>::eval(std::forward<F>(f),
std::forward<T>(t));
}
}
}
#endif