<commit_before>/*
 * Memory pool.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_POOL_HXX
#define BENG_PROXY_POOL_HXX

#include "trace.h"

#include <inline/compiler.h>

#include <utility>
#include <new>

#ifndef NDEBUG
#include <assert.h>
#endif

#include <stddef.h>
#include <stdbool.h>

struct pool;
struct SlicePool;
struct AllocatorStats;

struct pool_mark_state {
    /**
     * The area that was current when the mark was set.
     */
    struct linear_pool_area *area;

    /**
     * The area before #area.  This is used to dispose areas that were
     * inserted before the current area due to a large allocation.
     */
    struct linear_pool_area *prev;

    /**
     * The position within the current area when the mark was set.
     */
    size_t position;

#ifndef NDEBUG
    /**
     * Used in an assertion: if the pool was empty before pool_mark(),
     * it must be empty again after pool_rewind().
     */
    bool was_empty;
#endif
};

struct StringView;

void
pool_recycler_clear();

gcc_malloc
struct pool *
pool_new_libc(struct pool *parent, const char *name);

gcc_malloc
struct pool *
pool_new_linear(struct pool *parent, const char *name, size_t initial_size);

gcc_malloc
struct pool *
pool_new_slice(struct pool *parent, const char *name,
               struct SlicePool *slice_pool);

#ifdef NDEBUG

#define pool_set_major(pool)

#else

void
pool_set_major(struct pool *pool);

#endif

void
pool_ref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_ref(pool) pool_ref_impl(pool TRACE_ARGS)
#define pool_ref_fwd(pool) pool_ref_impl(pool TRACE_ARGS_FWD)

unsigned
pool_unref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_unref(pool) pool_unref_impl(pool TRACE_ARGS)
#define pool_unref_fwd(pool) pool_unref_impl(pool TRACE_ARGS_FWD)

class LinearPool {
    struct pool &p;

public:
    LinearPool(struct pool &parent, const char *name, size_t initial_size)
        :p(*pool_new_linear(&parent, name, initial_size)) {}

    ~LinearPool() {
        gcc_unused auto ref = pool_unref(&p);
#ifndef NDEBUG
        assert(ref == 0);
#endif
    }

    struct pool &get() {
        return p;
    }

    operator struct pool &() {
        return p;
    }

    operator struct pool *() {
        return &p;
    }
};

/**
 * Returns the total size of all allocations in this pool.
 */
gcc_pure
size_t
pool_netto_size(const struct pool *pool);

/**
 * Returns the total amount of memory allocated by this pool.
 */
gcc_pure
size_t
pool_brutto_size(const struct pool *pool);

/**
 * Returns the total size of this pool and all of its descendants
 * (recursively).
 */
gcc_pure
size_t
pool_recursive_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_recursive_brutto_size(const struct pool *pool);

/**
 * Returns the total size of all descendants of this pool (recursively).
 */
gcc_pure
size_t
pool_children_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_children_brutto_size(const struct pool *pool);

AllocatorStats
pool_children_stats(const struct pool &pool);

void
pool_dump_tree(const struct pool *pool);

#ifndef NDEBUG
#include <boost/intrusive/list.hpp>

struct pool_notify_state final
    : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

    struct pool *pool;

    const char *name;

    bool destroyed, registered;

#ifdef TRACE
    const char *file;
    int line;

    const char *destroyed_file;
    int destroyed_line;
#endif
};

void
pool_notify(struct pool *pool, struct pool_notify_state *notify);

bool
pool_denotify(struct pool_notify_state *notify);

/**
 * Hands over control from an existing #pool_notify to a new one.  The
 * old one is unregistered.
 */
void
pool_notify_move(struct pool *pool, struct pool_notify_state *src,
                 struct pool_notify_state *dest);

class PoolNotify {
    struct pool_notify_state state;

public:
    explicit PoolNotify(struct pool &pool) {
        pool_notify(&pool, &state);
    }

    PoolNotify(const PoolNotify &) = delete;

#ifndef NDEBUG
    ~PoolNotify() {
        assert(!state.registered);
    }
#endif

    bool Denotify() {
        return pool_denotify(&state);
    }
};

#endif

class ScopePoolRef {
    struct pool &pool;
#ifndef NDEBUG
    PoolNotify notify;
#endif

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

public:
    explicit ScopePoolRef(struct pool &_pool TRACE_ARGS_DECL_)
        :pool(_pool)
#ifndef NDEBUG
        , notify(_pool)
#endif
         TRACE_ARGS_INIT
    {
        pool_ref_fwd(&_pool);
    }

    ScopePoolRef(const ScopePoolRef &) = delete;

    ~ScopePoolRef() {
#ifndef NDEBUG
        notify.Denotify();
#endif
        pool_unref_fwd(&pool);
    }

    operator struct pool &() {
        return pool;
    }

    operator struct pool *() {
        return &pool;
    }
};

/**
 * Base class for classes which hold a reference to a #pool.
 */
class PoolHolder {
protected:
    struct pool &pool;

    explicit PoolHolder(struct pool &_pool)
        :pool(_pool)
    {
        pool_ref(&_pool);
    }

    PoolHolder(const PoolHolder &) = delete;
    PoolHolder &operator=(const PoolHolder &) = delete;

    ~PoolHolder() {
        pool_unref(&pool);
    }

    struct pool &GetPool() {
        return pool;
    }
};

#ifndef NDEBUG

void
pool_ref_notify_impl(struct pool *pool, struct pool_notify_state *notify TRACE_ARGS_DECL);

void
pool_unref_denotify_impl(struct pool *pool, struct pool_notify_state *notify
                         TRACE_ARGS_DECL);

/**
 * Do a "checked" pool reference.
 */
#define pool_ref_notify(pool, notify) \
    pool_ref_notify_impl(pool, notify TRACE_ARGS)

/**
 * Do a "checked" pool unreference.  If the pool has been destroyed,
 * an assertion will fail.  Double frees are also caught.
 */
#define pool_unref_denotify(pool, notify) \
    pool_unref_denotify_impl(pool, notify TRACE_ARGS)

#else
#define pool_ref_notify(pool, notify) pool_ref(pool)
#define pool_unref_denotify(pool, notify) pool_unref(pool)
#endif

#ifdef NDEBUG

static inline void
pool_trash(gcc_unused struct pool *pool)
{
}

static inline void
pool_commit()
{
}

static inline void
pool_attach(gcc_unused struct pool *pool, gcc_unused const void *p,
            gcc_unused const char *name)
{
}

static inline void
pool_attach_checked(gcc_unused struct pool *pool, gcc_unused const void *p,
                    gcc_unused const char *name)
{
}

static inline void
pool_detach(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline void
pool_detach_checked(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline const char *
pool_attachment_name(gcc_unused struct pool *pool, gcc_unused const void *p)
{
    return NULL;
}

#else

void
pool_trash(struct pool *pool);

void
pool_commit();

bool
pool_contains(struct pool *pool, const void *ptr, size_t size);

/**
 * Attach an opaque object to the pool.  It must be detached before
 * the pool is destroyed.  This is used in debugging mode to track
 * whether all external objects have been destroyed.
 */
void
pool_attach(struct pool *pool, const void *p, const char *name);

/**
 * Same as pool_attach(), but checks if the object is already
 * registered.
 */
void
pool_attach_checked(struct pool *pool, const void *p, const char *name);

void
pool_detach(struct pool *pool, const void *p);

void
pool_detach_checked(struct pool *pool, const void *p);

const char *
pool_attachment_name(struct pool *pool, const void *p);

#endif

void
pool_mark(struct pool *pool, struct pool_mark_state *mark);

void
pool_rewind(struct pool *pool, const struct pool_mark_state *mark);

class AutoRewindPool {
    struct pool &pool;
    pool_mark_state mark;

public:
    AutoRewindPool(struct pool &_pool):pool(_pool) {
        pool_mark(&pool, &mark);
    }

    AutoRewindPool(const AutoRewindPool &) = delete;

    ~AutoRewindPool() {
        pool_rewind(&pool, &mark);
    }
};

gcc_malloc
void *
p_malloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_malloc(pool, size) p_malloc_impl(pool, size TRACE_ARGS)
#define p_malloc_fwd(pool, size) p_malloc_impl(pool, size TRACE_ARGS_FWD)

void
p_free(struct pool *pool, const void *ptr);

gcc_malloc
void *
p_calloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_calloc(pool, size) p_calloc_impl(pool, size TRACE_ARGS)

gcc_malloc
void *
p_memdup_impl(struct pool *pool, const void *src, size_t length TRACE_ARGS_DECL);

#define p_memdup(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS)
#define p_memdup_fwd(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strdup_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup(pool, src) p_strdup_impl(pool, src TRACE_ARGS)
#define p_strdup_fwd(pool, src) p_strdup_impl(pool, src TRACE_ARGS_FWD)

static inline const char *
p_strdup_checked(struct pool *pool, const char *s)
{
    return s == NULL ? NULL : p_strdup(pool, s);
}

gcc_malloc
char *
p_strdup_lower_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup_lower(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS)
#define p_strdup_lower_fwd(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS)
#define p_strndup_fwd(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_lower_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup_lower(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS)
#define p_strndup_lower_fwd(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc gcc_printf(2, 3)
char *
p_sprintf(struct pool *pool, const char *fmt, ...);

gcc_malloc
char *
p_strcat(struct pool *pool, const char *s, ...);

gcc_malloc
char *
p_strncat(struct pool *pool, const char *s, size_t length, ...);

template<typename T>
T *
PoolAlloc(pool &p)
{
    return (T *)p_malloc(&p, sizeof(T));
}

template<typename T>
T *
PoolAlloc(pool &p, size_t n)
{
    return (T *)p_malloc(&p, sizeof(T) * n);
}

template<>
inline void *
PoolAlloc<void>(pool &p, size_t n)
{
    return p_malloc(&p, n);
}

template<typename T, typename... Args>
T *
NewFromPool(pool &p, Args&&... args)
{
    void *t = PoolAlloc<T>(p);
    return ::new(t) T(std::forward<Args>(args)...);
}

template<typename T>
void
DeleteFromPool(struct pool &pool, T *t)
{
    t->~T();
    p_free(&pool, t);
}

/**
 * A disposer for boost::intrusive that invokes the DeleteFromPool()
 * on the given pointer.
 */
class PoolDisposer {
    struct pool &p;

public:
    explicit PoolDisposer(struct pool &_p):p(_p) {}

    template<typename T>
    void operator()(T *t) {
        DeleteFromPool(p, t);
    }
};

template<typename T>
void
DeleteUnrefPool(struct pool &pool, T *t)
{
    DeleteFromPool(pool, t);
    pool_unref(&pool);
}

template<typename T>
void
DeleteUnrefTrashPool(struct pool &pool, T *t)
{
    pool_trash(&pool);
    DeleteUnrefPool(pool, t);
}

class PoolAllocator {
    struct pool &pool;

public:
    explicit constexpr PoolAllocator(struct pool &_pool):pool(_pool) {}

    void *Allocate(size_t size) {
        return p_malloc(&pool, size);
    }

    char *DupString(const char *p) {
        return p_strdup(&pool, p);
    }

    void Free(void *p) {
        p_free(&pool, p);
    }

    template<typename T, typename... Args>
    T *New(Args&&... args) {
        return NewFromPool<T>(pool, std::forward<Args>(args)...);
    }

    template<typename T>
    void Delete(T *t) {
        DeleteFromPool(pool, t);
    }
};

gcc_malloc
char *
p_strdup_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

gcc_malloc
char *
p_strdup_lower_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

#endif
<commit_msg>pool: allow PoolAlloc() only for trivial types<commit_after>/*
 * Memory pool.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_POOL_HXX
#define BENG_PROXY_POOL_HXX

#include "trace.h"

#include <inline/compiler.h>

#include <type_traits>
#include <utility>
#include <new>

#ifndef NDEBUG
#include <assert.h>
#endif

#include <stddef.h>
#include <stdbool.h>

struct pool;
struct SlicePool;
struct AllocatorStats;

struct pool_mark_state {
    /**
     * The area that was current when the mark was set.
     */
    struct linear_pool_area *area;

    /**
     * The area before #area.  This is used to dispose areas that were
     * inserted before the current area due to a large allocation.
     */
    struct linear_pool_area *prev;

    /**
     * The position within the current area when the mark was set.
     */
    size_t position;

#ifndef NDEBUG
    /**
     * Used in an assertion: if the pool was empty before pool_mark(),
     * it must be empty again after pool_rewind().
     */
    bool was_empty;
#endif
};

struct StringView;

void
pool_recycler_clear();

gcc_malloc
struct pool *
pool_new_libc(struct pool *parent, const char *name);

gcc_malloc
struct pool *
pool_new_linear(struct pool *parent, const char *name, size_t initial_size);

gcc_malloc
struct pool *
pool_new_slice(struct pool *parent, const char *name,
               struct SlicePool *slice_pool);

#ifdef NDEBUG

#define pool_set_major(pool)

#else

void
pool_set_major(struct pool *pool);

#endif

void
pool_ref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_ref(pool) pool_ref_impl(pool TRACE_ARGS)
#define pool_ref_fwd(pool) pool_ref_impl(pool TRACE_ARGS_FWD)

unsigned
pool_unref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_unref(pool) pool_unref_impl(pool TRACE_ARGS)
#define pool_unref_fwd(pool) pool_unref_impl(pool TRACE_ARGS_FWD)

class LinearPool {
    struct pool &p;

public:
    LinearPool(struct pool &parent, const char *name, size_t initial_size)
        :p(*pool_new_linear(&parent, name, initial_size)) {}

    ~LinearPool() {
        gcc_unused auto ref = pool_unref(&p);
#ifndef NDEBUG
        assert(ref == 0);
#endif
    }

    struct pool &get() {
        return p;
    }

    operator struct pool &() {
        return p;
    }

    operator struct pool *() {
        return &p;
    }
};

/**
 * Returns the total size of all allocations in this pool.
 */
gcc_pure
size_t
pool_netto_size(const struct pool *pool);

/**
 * Returns the total amount of memory allocated by this pool.
 */
gcc_pure
size_t
pool_brutto_size(const struct pool *pool);

/**
 * Returns the total size of this pool and all of its descendants
 * (recursively).
 */
gcc_pure
size_t
pool_recursive_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_recursive_brutto_size(const struct pool *pool);

/**
 * Returns the total size of all descendants of this pool (recursively).
 */
gcc_pure
size_t
pool_children_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_children_brutto_size(const struct pool *pool);

AllocatorStats
pool_children_stats(const struct pool &pool);

void
pool_dump_tree(const struct pool *pool);

#ifndef NDEBUG
#include <boost/intrusive/list.hpp>

struct pool_notify_state final
    : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

    struct pool *pool;

    const char *name;

    bool destroyed, registered;

#ifdef TRACE
    const char *file;
    int line;

    const char *destroyed_file;
    int destroyed_line;
#endif
};

void
pool_notify(struct pool *pool, struct pool_notify_state *notify);

bool
pool_denotify(struct pool_notify_state *notify);

/**
 * Hands over control from an existing #pool_notify to a new one.  The
 * old one is unregistered.
 */
void
pool_notify_move(struct pool *pool, struct pool_notify_state *src,
                 struct pool_notify_state *dest);

class PoolNotify {
    struct pool_notify_state state;

public:
    explicit PoolNotify(struct pool &pool) {
        pool_notify(&pool, &state);
    }

    PoolNotify(const PoolNotify &) = delete;

#ifndef NDEBUG
    ~PoolNotify() {
        assert(!state.registered);
    }
#endif

    bool Denotify() {
        return pool_denotify(&state);
    }
};

#endif

class ScopePoolRef {
    struct pool &pool;
#ifndef NDEBUG
    PoolNotify notify;
#endif

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

public:
    explicit ScopePoolRef(struct pool &_pool TRACE_ARGS_DECL_)
        :pool(_pool)
#ifndef NDEBUG
        , notify(_pool)
#endif
         TRACE_ARGS_INIT
    {
        pool_ref_fwd(&_pool);
    }

    ScopePoolRef(const ScopePoolRef &) = delete;

    ~ScopePoolRef() {
#ifndef NDEBUG
        notify.Denotify();
#endif
        pool_unref_fwd(&pool);
    }

    operator struct pool &() {
        return pool;
    }

    operator struct pool *() {
        return &pool;
    }
};

/**
 * Base class for classes which hold a reference to a #pool.
 */
class PoolHolder {
protected:
    struct pool &pool;

    explicit PoolHolder(struct pool &_pool)
        :pool(_pool)
    {
        pool_ref(&_pool);
    }

    PoolHolder(const PoolHolder &) = delete;
    PoolHolder &operator=(const PoolHolder &) = delete;

    ~PoolHolder() {
        pool_unref(&pool);
    }

    struct pool &GetPool() {
        return pool;
    }
};

#ifndef NDEBUG

void
pool_ref_notify_impl(struct pool *pool, struct pool_notify_state *notify TRACE_ARGS_DECL);

void
pool_unref_denotify_impl(struct pool *pool, struct pool_notify_state *notify
                         TRACE_ARGS_DECL);

/**
 * Do a "checked" pool reference.
 */
#define pool_ref_notify(pool, notify) \
    pool_ref_notify_impl(pool, notify TRACE_ARGS)

/**
 * Do a "checked" pool unreference.  If the pool has been destroyed,
 * an assertion will fail.  Double frees are also caught.
 */
#define pool_unref_denotify(pool, notify) \
    pool_unref_denotify_impl(pool, notify TRACE_ARGS)

#else
#define pool_ref_notify(pool, notify) pool_ref(pool)
#define pool_unref_denotify(pool, notify) pool_unref(pool)
#endif

#ifdef NDEBUG

static inline void
pool_trash(gcc_unused struct pool *pool)
{
}

static inline void
pool_commit()
{
}

static inline void
pool_attach(gcc_unused struct pool *pool, gcc_unused const void *p,
            gcc_unused const char *name)
{
}

static inline void
pool_attach_checked(gcc_unused struct pool *pool, gcc_unused const void *p,
                    gcc_unused const char *name)
{
}

static inline void
pool_detach(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline void
pool_detach_checked(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline const char *
pool_attachment_name(gcc_unused struct pool *pool, gcc_unused const void *p)
{
    return NULL;
}

#else

void
pool_trash(struct pool *pool);

void
pool_commit();

bool
pool_contains(struct pool *pool, const void *ptr, size_t size);

/**
 * Attach an opaque object to the pool.  It must be detached before
 * the pool is destroyed.  This is used in debugging mode to track
 * whether all external objects have been destroyed.
 */
void
pool_attach(struct pool *pool, const void *p, const char *name);

/**
 * Same as pool_attach(), but checks if the object is already
 * registered.
 */
void
pool_attach_checked(struct pool *pool, const void *p, const char *name);

void
pool_detach(struct pool *pool, const void *p);

void
pool_detach_checked(struct pool *pool, const void *p);

const char *
pool_attachment_name(struct pool *pool, const void *p);

#endif

void
pool_mark(struct pool *pool, struct pool_mark_state *mark);

void
pool_rewind(struct pool *pool, const struct pool_mark_state *mark);

class AutoRewindPool {
    struct pool &pool;
    pool_mark_state mark;

public:
    AutoRewindPool(struct pool &_pool):pool(_pool) {
        pool_mark(&pool, &mark);
    }

    AutoRewindPool(const AutoRewindPool &) = delete;

    ~AutoRewindPool() {
        pool_rewind(&pool, &mark);
    }
};

gcc_malloc
void *
p_malloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_malloc(pool, size) p_malloc_impl(pool, size TRACE_ARGS)
#define p_malloc_fwd(pool, size) p_malloc_impl(pool, size TRACE_ARGS_FWD)

void
p_free(struct pool *pool, const void *ptr);

gcc_malloc
void *
p_calloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_calloc(pool, size) p_calloc_impl(pool, size TRACE_ARGS)

gcc_malloc
void *
p_memdup_impl(struct pool *pool, const void *src, size_t length TRACE_ARGS_DECL);

#define p_memdup(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS)
#define p_memdup_fwd(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strdup_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup(pool, src) p_strdup_impl(pool, src TRACE_ARGS)
#define p_strdup_fwd(pool, src) p_strdup_impl(pool, src TRACE_ARGS_FWD)

static inline const char *
p_strdup_checked(struct pool *pool, const char *s)
{
    return s == NULL ? NULL : p_strdup(pool, s);
}

gcc_malloc
char *
p_strdup_lower_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup_lower(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS)
#define p_strdup_lower_fwd(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS)
#define p_strndup_fwd(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_lower_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup_lower(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS)
#define p_strndup_lower_fwd(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc gcc_printf(2, 3)
char *
p_sprintf(struct pool *pool, const char *fmt, ...);

gcc_malloc
char *
p_strcat(struct pool *pool, const char *s, ...);

gcc_malloc
char *
p_strncat(struct pool *pool, const char *s, size_t length, ...);

template<typename T>
T *
PoolAlloc(pool &p)
{
#if CLANG_OR_GCC_VERSION(5,0)
    static_assert(std::is_trivially_default_constructible<T>::value,
                  "Must be trivially constructible");
#else
    static_assert(std::has_trivial_default_constructor<T>::value,
                  "Must be trivially constructible");
#endif

    return (T *)p_malloc(&p, sizeof(T));
}

template<typename T>
T *
PoolAlloc(pool &p, size_t n)
{
#if CLANG_OR_GCC_VERSION(5,0)
    static_assert(std::is_trivially_default_constructible<T>::value,
                  "Must be trivially constructible");
#else
    static_assert(std::has_trivial_default_constructor<T>::value,
                  "Must be trivially constructible");
#endif

    return (T *)p_malloc(&p, sizeof(T) * n);
}

template<>
inline void *
PoolAlloc<void>(pool &p, size_t n)
{
    return p_malloc(&p, n);
}

template<typename T, typename... Args>
T *
NewFromPool(pool &p, Args&&... args)
{
    void *t = p_malloc(&p, sizeof(T));
    return ::new(t) T(std::forward<Args>(args)...);
}

template<typename T>
void
DeleteFromPool(struct pool &pool, T *t)
{
    t->~T();
    p_free(&pool, t);
}

/**
 * A disposer for boost::intrusive that invokes the DeleteFromPool()
 * on the given pointer.
 */
class PoolDisposer {
    struct pool &p;

public:
    explicit PoolDisposer(struct pool &_p):p(_p) {}

    template<typename T>
    void operator()(T *t) {
        DeleteFromPool(p, t);
    }
};

template<typename T>
void
DeleteUnrefPool(struct pool &pool, T *t)
{
    DeleteFromPool(pool, t);
    pool_unref(&pool);
}

template<typename T>
void
DeleteUnrefTrashPool(struct pool &pool, T *t)
{
    pool_trash(&pool);
    DeleteUnrefPool(pool, t);
}

class PoolAllocator {
    struct pool &pool;

public:
    explicit constexpr PoolAllocator(struct pool &_pool):pool(_pool) {}

    void *Allocate(size_t size) {
        return p_malloc(&pool, size);
    }

    char *DupString(const char *p) {
        return p_strdup(&pool, p);
    }

    void Free(void *p) {
        p_free(&pool, p);
    }

    template<typename T, typename... Args>
    T *New(Args&&... args) {
        return NewFromPool<T>(pool, std::forward<Args>(args)...);
    }

    template<typename T>
    void Delete(T *t) {
        DeleteFromPool(pool, t);
    }
};

gcc_malloc
char *
p_strdup_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

gcc_malloc
char *
p_strdup_lower_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>

void helpCheck(char *argv[]) {
	if (argv[1] == std::string("-h") || argv[1] == std::string("--help")) {
		std::cout << "\nptxv - Parallel Tar XZ by Ryan Chui (2017)\n" << std::endl;
		exit(0);
	}
}

char cwd [PATH_MAX];

int main(int argc, char *argv[]) {
	helpCheck(argv);
	getcwd(cwd, PATH_MAX);
	return 0;
}
<commit_msg>Implemented recursive file counting<commit_after>#include <iostream>
#include <unistd.h>
#include <dirent.h>

void helpCheck(char *argv[]) {
	if (argv[1] == std::string("-h") || argv[1] == std::string("--help")) {
		std::cout << "\nptxv - Parallel Tar XZ by Ryan Chui (2017)\n" << std::endl;
		exit(0);
	}
}

void findAll(int *numFiles, const char *cwd) {
	DIR *dir;
	struct dirent *ent;

	// Check if cwd is a directory
	if ((dir = opendir(cwd)) != NULL) {
		// Get all file paths within directory.
		while ((ent = readdir (dir)) != NULL) {
			std::string fileBuff = std::string(ent -> d_name);
			if (fileBuff != "." && fileBuff != "..") {
				DIR *dir2;
				std::string filePath = std::string(cwd) + "/" + fileBuff;
				// Check if file path is a directory.
				if ((dir2 = opendir(filePath.c_str())) != NULL) {
					closedir(dir2);
					findAll(numFiles, filePath.c_str());
				} else {
					*numFiles += 1;
				}
			}
		}
	}
}

char cwd [PATH_MAX];

int main(int argc, char *argv[]) {
	int *numFiles = new int(0);

	if (argc > 1) {
		helpCheck(argv);
	}
	getcwd(cwd, PATH_MAX);
	std::cout << cwd << std::endl;
	findAll(numFiles, cwd);

	delete(numFiles);
	return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (C) Alexandr Vorontsov. 2017
// Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
//

#include "stdafx.h"

#include <Kioto.h>

#include <windows.h>

void OnEngineInited()
{
    Kioto::Scene* scene = new Kioto::Scene();
    Kioto::SetScene(scene);
    OutputDebugStringA("init engine");
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int nCmdShow)
{
    Kioto::KiotoMain(hInstance, prevInstance, cmdLine, nCmdShow, L"Kioto game", OnEngineInited);
    return 0;
}
<commit_msg>Add test scene with test scene system.<commit_after>//
// Copyright (C) Alexandr Vorontsov. 2017
// Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
//

#include "stdafx.h"

#include <Kioto.h>

#include <windows.h>

class TestScene : public Kioto::Scene
{
public:
    ~TestScene()
    {
    }
};

class TestSceneSystem : public Kioto::SceneSystem
{
public:
    void Update(float32 dt) override
    {
    }
    ~TestSceneSystem()
    {
    }
};

void OnEngineInited()
{
    Kioto::Scene* scene = new TestScene();
    scene->AddSystem(new TestSceneSystem{});
    Kioto::SetScene(scene);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int nCmdShow)
{
    Kioto::KiotoMain(hInstance, prevInstance, cmdLine, nCmdShow, L"Kioto game", OnEngineInited);
    return 0;
}
<|endoftext|>


<commit_before>#include "ReQL-test.hpp"

#include "catch.h"

#include <limits>

using namespace ReQL;

TEST_CASE("Connection", "[c++][connect]") {
  Connection conn = connect();

  REQUIRE(conn.isOpen());
}

TEST_CASE("Expr", "[c][expr]") {
  SECTION("null") {
    _ReQL_Op_t null;

    _reql_null_init(&null);

    CHECK(_reql_datum_type(&null) == _REQL_R_NULL);
  }
  SECTION("number") {
    _ReQL_Op_t num;

    const double val = 42.0;

    _reql_number_init(&num, val);

    CHECK(val == _reql_to_number(&num));
  }
  SECTION("number edges") {
    _ReQL_Op_t num;

    const double val = std::numeric_limits<std::double_t>::max();

    _reql_number_init(&num, val);

    CHECK(val == _reql_to_number(&num));
  }
  SECTION("string") {
    _ReQL_Op_t string;

    const uint32_t size = 12;

    uint8_t buf[size] = "Hello World";

    std::string orig = std::string((char *)buf, size);

    _reql_string_init(&string, buf, size, size);

    CHECK(orig.compare(0, size, (char *)_reql_string_buf(&string), size) == 0);
    CHECK(size == _reql_string_size(&string));
  }
}
<commit_msg>Add bool c constructor test.<commit_after>#include "ReQL-test.hpp"

#include "catch.h"

#include <limits>

using namespace ReQL;

TEST_CASE("Connection", "[c++][connect]") {
  Connection conn = connect();

  REQUIRE(conn.isOpen());
}

TEST_CASE("Expr", "[c][expr]") {
  SECTION("bool") {
    _ReQL_Op_t boolean;

    _reql_bool_init(&boolean, 10);

    CHECK(_reql_to_bool(&boolean) == true);

    _reql_bool_init(&boolean, false);

    CHECK(_reql_to_bool(&boolean) == false);
  }
  SECTION("null") {
    _ReQL_Op_t null;

    _reql_null_init(&null);

    CHECK(_reql_datum_type(&null) == _REQL_R_NULL);
  }
  SECTION("number") {
    _ReQL_Op_t num;

    const double val = 42.0;

    _reql_number_init(&num, val);

    CHECK(val == _reql_to_number(&num));
  }
  SECTION("number edges") {
    _ReQL_Op_t num;

    const double val = std::numeric_limits<std::double_t>::max();

    _reql_number_init(&num, val);

    CHECK(val == _reql_to_number(&num));
  }
  SECTION("string") {
    _ReQL_Op_t string;

    const uint32_t size = 12;

    uint8_t buf[size] = "Hello World";

    std::string orig = std::string((char *)buf, size);

    _reql_string_init(&string, buf, size, size);

    CHECK(orig.compare(0, size, (char *)_reql_string_buf(&string), size) == 0);
    CHECK(size == _reql_string_size(&string));
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, elvman
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "RealisticWater.h"

RealisticWaterSceneNode::RealisticWaterSceneNode(scene::ISceneManager* sceneManager, f32 width, f32 height,
												 const irr::core::stringc& resourcePath, core::dimension2du renderTargetSize,
												 scene::ISceneNode* parent, s32 id):
	scene::ISceneNode(parent, sceneManager, id), _time(0),
	_size(width, height), _sceneManager(sceneManager), _refractionMap(NULL), _reflectionMap(NULL),
	_windForce(20.0f),_windDirection(0, 1),_waveHeight(0.3f), _waterColor(0.1f, 0.1f, 0.6f, 1.0f), _colorBlendFactor(0.2f), _camera(NULL)
{
	_videoDriver = sceneManager->getVideoDriver();

	//create new camera
	_camera = sceneManager->addCameraSceneNode(0, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), -1, false);

	_waterMesh = sceneManager->addHillPlaneMesh("RealisticWater", _size, core::dimension2d<u32>(1, 1));

	_waterSceneNode = sceneManager->addMeshSceneNode(_waterMesh->getMesh(0), this);

	video::IGPUProgrammingServices* GPUProgrammingServices = _videoDriver->getGPUProgrammingServices();

	core::stringc waterPixelShader;
	core::stringc waterVertexShader;

	if (_videoDriver->getDriverType() == video::EDT_DIRECT3D9)
	{
		waterPixelShader = resourcePath + "/shaders/Water_ps.hlsl";
		waterVertexShader = resourcePath + "/shaders/Water_vs.hlsl";
	}
	else if (_videoDriver->getDriverType() == video::EDT_OPENGL)
	{
		waterPixelShader = resourcePath + "/shaders/Water_ps.glsl";
		waterVertexShader = resourcePath + "/shaders/Water_vs.glsl";
	}

	_shaderMaterial = GPUProgrammingServices->addHighLevelShaderMaterialFromFiles(
		waterVertexShader.c_str(), "main", video::EVST_VS_1_1,
		waterPixelShader.c_str(), "main", video::EPST_PS_1_1,
		this);

	_waterSceneNode->setMaterialType((video::E_MATERIAL_TYPE)_shaderMaterial);

	irr::video::ITexture* bumpTexture = _videoDriver->getTexture(resourcePath + "/waterbump.png");
	_waterSceneNode->setMaterialTexture(0, bumpTexture);

	_refractionMap = _videoDriver->addRenderTargetTexture(renderTargetSize);
	_reflectionMap = _videoDriver->addRenderTargetTexture(renderTargetSize);

	_waterSceneNode->setMaterialTexture(1, _refractionMap);
	_waterSceneNode->setMaterialTexture(2, _reflectionMap);
}

RealisticWaterSceneNode::~RealisticWaterSceneNode()
{
	if (_camera)
	{
		_camera->drop();
		_camera = NULL;
	}

	if (_refractionMap)
	{
		_refractionMap->drop();
		_refractionMap = NULL;
	}

	if (_reflectionMap)
	{
		_reflectionMap->drop();
		_reflectionMap = NULL;
	}

	if (_waterSceneNode)
	{
		_waterSceneNode->drop();
		_waterSceneNode = NULL;
	}

	if (_waterMesh)
	{
		_waterMesh->drop();
		_waterMesh = NULL;
	}
}

// frame
void RealisticWaterSceneNode::OnRegisterSceneNode()
{
	ISceneNode::OnRegisterSceneNode();

	if (IsVisible)
	{
		_sceneManager->registerNodeForRendering(this);
	}
}

void RealisticWaterSceneNode::OnAnimate(u32 timeMs)
{
	ISceneNode::OnAnimate(timeMs);

	_time = timeMs;

	//fixes glitches with incomplete refraction
	const f32 CLIP_PLANE_OFFSET_Y = 5.0f;

	if (IsVisible)
	{
		setVisible(false); //hide the water

		//refraction
		_videoDriver->setRenderTarget(_refractionMap, true, true); //render to refraction

		//refraction clipping plane
		core::plane3d<f32> refractionClipPlane(0, RelativeTranslation.Y + CLIP_PLANE_OFFSET_Y, 0, 0, -1, 0); //refraction clip plane
		_videoDriver->setClipPlane(0, refractionClipPlane, true);

		_sceneManager->drawAll(); //draw the scene

		//reflection
		_videoDriver->setRenderTarget(_reflectionMap, true, true); //render to reflection

		//get current camera
		scene::ICameraSceneNode* currentCamera = _sceneManager->getActiveCamera();

		//set FOV anf far value from current camera
		_camera->setFarValue(currentCamera->getFarValue());
		_camera->setFOV(currentCamera->getFOV());

		core::vector3df position = currentCamera->getAbsolutePosition();
		position.Y = -position.Y + 2 * RelativeTranslation.Y; //position of the water
		_camera->setPosition(position);

		core::vector3df target = currentCamera->getTarget();

		//invert Y position of current camera
		target.Y = -target.Y + 2 * RelativeTranslation.Y;
		_camera->setTarget(target);

		//set the reflection camera
		_sceneManager->setActiveCamera(_camera);

		//reflection clipping plane
		core::plane3d<f32> reflectionClipPlane(0, RelativeTranslation.Y - CLIP_PLANE_OFFSET_Y, 0, 0, 1, 0);
		_videoDriver->setClipPlane(0, reflectionClipPlane, true);

		_sceneManager->drawAll(); //draw the scene

		//disable clip plane
		_videoDriver->enableClipPlane(0, false);

		//set back old render target
		_videoDriver->setRenderTarget(0, false, true);

		//set back the active camera
		_sceneManager->setActiveCamera(currentCamera);

		setVisible(true); //show it again
	}
}

void RealisticWaterSceneNode::render()
{
	/*core::array<video::IRenderTarget> renderTargets;
	//renderTargets.push_back();
	renderTargets.push_back(_refractionMap);

	_videoDriver->setRenderTarget(renderTargets, true, true);*/
	//_videoDriver->draw2DImage(_reflectionMap,core::position2d<s32>(0,0));
}

// returns the axis aligned bounding box of terrain
const core::aabbox3d<f32>& RealisticWaterSceneNode::getBoundingBox() const
{
	return _waterSceneNode->getBoundingBox();
}

void RealisticWaterSceneNode::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
	video::IVideoDriver* driver = services->getVideoDriver();

	core::matrix4 projection = driver->getTransform(video::ETS_PROJECTION);
	core::matrix4 view = driver->getTransform(video::ETS_VIEW);
	core::matrix4 world = driver->getTransform(video::ETS_WORLD);

	core::matrix4 cameraView = _camera->getViewMatrix();

	//vertex shader constants
	//services->setVertexShaderConstant("View", view.pointer(), 16);

	core::matrix4 worldViewProj = projection;
	worldViewProj *= view;
	worldViewProj *= world;
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldViewProj"), worldViewProj.pointer(), 16);

	core::matrix4 worldReflectionViewProj = projection;
	worldReflectionViewProj *= cameraView;
	worldReflectionViewProj *= world;

	services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldReflectionViewProj"), worldReflectionViewProj.pointer(), 16);

	f32 waveLength = 0.1f;
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WaveLength"), &waveLength, 1);

	f32 time = _time / 100000.0f;
	services->setVertexShaderConstant(services->getVertexShaderConstantID("Time"), &time, 1);

	services->setVertexShaderConstant(services->getVertexShaderConstantID("WindForce"), &_windForce, 1);

	services->setVertexShaderConstant(services->getVertexShaderConstantID("WindDirection"), &_windDirection.X, 2);

	//pixel shader constants
	core::vector3df cameraPosition = _sceneManager->getActiveCamera()->getPosition();
	services->setPixelShaderConstant(services->getVertexShaderConstantID("CameraPosition"), &cameraPosition.X, 3);

	services->setPixelShaderConstant(services->getVertexShaderConstantID("WaveHeight"), &_waveHeight, 1);

	services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterColor"), &_waterColor.r, 4);

	services->setPixelShaderConstant(services->getVertexShaderConstantID("ColorBlendFactor"), &_colorBlendFactor, 1);

	//texture constants for GLSL
	if (driver->getDriverType() == video::EDT_OPENGL)
	{
		int var0 = 0;
		int var1 = 1;
		int var2 = 2;
		services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterBump"), &var0, 1); //the colormap
		services->setPixelShaderConstant(services->getVertexShaderConstantID("RefractionMap"), &var1, 1); //the colormap
		services->setPixelShaderConstant(services->getVertexShaderConstantID("ReflectionMap"), &var2, 1); //the colormap
	}
}

void RealisticWaterSceneNode::setWindForce(const f32 windForce)
{
	_windForce = windForce;
}

void RealisticWaterSceneNode::setWindDirection(const core::vector2df& windDirection)
{
	_windDirection = windDirection;
	_windDirection.normalize();
}

void RealisticWaterSceneNode::setWaveHeight(const f32 waveHeight)
{
	_waveHeight = waveHeight;
}

void RealisticWaterSceneNode::setWaterColor(const video::SColorf& waterColor)
{
	_waterColor = waterColor;
}

void RealisticWaterSceneNode::setColorBlendFactor(const f32 colorBlendFactor)
{
	_colorBlendFactor = colorBlendFactor;
}
<commit_msg>Added support for Irrlicht 1.8 and older versions<commit_after>/*
 * Copyright (c) 2013, elvman
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "RealisticWater.h"

RealisticWaterSceneNode::RealisticWaterSceneNode(scene::ISceneManager* sceneManager, f32 width, f32 height,
												 const irr::core::stringc& resourcePath, core::dimension2du renderTargetSize,
												 scene::ISceneNode* parent, s32 id):
	scene::ISceneNode(parent, sceneManager, id), _time(0),
	_size(width, height), _sceneManager(sceneManager), _refractionMap(NULL), _reflectionMap(NULL),
	_windForce(20.0f),_windDirection(0, 1),_waveHeight(0.3f), _waterColor(0.1f, 0.1f, 0.6f, 1.0f), _colorBlendFactor(0.2f), _camera(NULL)
{
	_videoDriver = sceneManager->getVideoDriver();

	//create new camera
	_camera = sceneManager->addCameraSceneNode(0, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), -1, false);

	_waterMesh = sceneManager->addHillPlaneMesh("RealisticWater", _size, core::dimension2d<u32>(1, 1));

	_waterSceneNode = sceneManager->addMeshSceneNode(_waterMesh->getMesh(0), this);

	video::IGPUProgrammingServices* GPUProgrammingServices = _videoDriver->getGPUProgrammingServices();

	core::stringc waterPixelShader;
	core::stringc waterVertexShader;

	if (_videoDriver->getDriverType() == video::EDT_DIRECT3D9)
	{
		waterPixelShader = resourcePath + "/shaders/Water_ps.hlsl";
		waterVertexShader = resourcePath + "/shaders/Water_vs.hlsl";
	}
	else if (_videoDriver->getDriverType() == video::EDT_OPENGL)
	{
		waterPixelShader = resourcePath + "/shaders/Water_ps.glsl";
		waterVertexShader = resourcePath + "/shaders/Water_vs.glsl";
	}

	_shaderMaterial = GPUProgrammingServices->addHighLevelShaderMaterialFromFiles(
		waterVertexShader.c_str(), "main", video::EVST_VS_1_1,
		waterPixelShader.c_str(), "main", video::EPST_PS_1_1,
		this);

	_waterSceneNode->setMaterialType((video::E_MATERIAL_TYPE)_shaderMaterial);

	irr::video::ITexture* bumpTexture = _videoDriver->getTexture(resourcePath + "/waterbump.png");
	_waterSceneNode->setMaterialTexture(0, bumpTexture);

	_refractionMap = _videoDriver->addRenderTargetTexture(renderTargetSize);
	_reflectionMap = _videoDriver->addRenderTargetTexture(renderTargetSize);

	_waterSceneNode->setMaterialTexture(1, _refractionMap);
	_waterSceneNode->setMaterialTexture(2, _reflectionMap);
}

RealisticWaterSceneNode::~RealisticWaterSceneNode()
{
	if (_camera)
	{
		_camera->drop();
		_camera = NULL;
	}

	if (_refractionMap)
	{
		_refractionMap->drop();
		_refractionMap = NULL;
	}

	if (_reflectionMap)
	{
		_reflectionMap->drop();
		_reflectionMap = NULL;
	}

	if (_waterSceneNode)
	{
		_waterSceneNode->drop();
		_waterSceneNode = NULL;
	}

	if (_waterMesh)
	{
		_waterMesh->drop();
		_waterMesh = NULL;
	}
}

// frame
void RealisticWaterSceneNode::OnRegisterSceneNode()
{
	ISceneNode::OnRegisterSceneNode();

	if (IsVisible)
	{
		_sceneManager->registerNodeForRendering(this);
	}
}

void RealisticWaterSceneNode::OnAnimate(u32 timeMs)
{
	ISceneNode::OnAnimate(timeMs);

	_time = timeMs;

	//fixes glitches with incomplete refraction
	const f32 CLIP_PLANE_OFFSET_Y = 5.0f;

	if (IsVisible)
	{
		setVisible(false); //hide the water

		//refraction
		_videoDriver->setRenderTarget(_refractionMap, true, true); //render to refraction

		//refraction clipping plane
		core::plane3d<f32> refractionClipPlane(0, RelativeTranslation.Y + CLIP_PLANE_OFFSET_Y, 0, 0, -1, 0); //refraction clip plane
		_videoDriver->setClipPlane(0, refractionClipPlane, true);

		_sceneManager->drawAll(); //draw the scene

		//reflection
		_videoDriver->setRenderTarget(_reflectionMap, true, true); //render to reflection

		//get current camera
		scene::ICameraSceneNode* currentCamera = _sceneManager->getActiveCamera();

		//set FOV anf far value from current camera
		_camera->setFarValue(currentCamera->getFarValue());
		_camera->setFOV(currentCamera->getFOV());

		core::vector3df position = currentCamera->getAbsolutePosition();
		position.Y = -position.Y + 2 * RelativeTranslation.Y; //position of the water
		_camera->setPosition(position);

		core::vector3df target = currentCamera->getTarget();

		//invert Y position of current camera
		target.Y = -target.Y + 2 * RelativeTranslation.Y;
		_camera->setTarget(target);

		//set the reflection camera
		_sceneManager->setActiveCamera(_camera);

		//reflection clipping plane
		core::plane3d<f32> reflectionClipPlane(0, RelativeTranslation.Y - CLIP_PLANE_OFFSET_Y, 0, 0, 1, 0);
		_videoDriver->setClipPlane(0, reflectionClipPlane, true);

		_sceneManager->drawAll(); //draw the scene

		//disable clip plane
		_videoDriver->enableClipPlane(0, false);

		//set back old render target
		_videoDriver->setRenderTarget(0, false, true);

		//set back the active camera
		_sceneManager->setActiveCamera(currentCamera);

		setVisible(true); //show it again
	}
}

void RealisticWaterSceneNode::render()
{
	/*core::array<video::IRenderTarget> renderTargets;
	//renderTargets.push_back();
	renderTargets.push_back(_refractionMap);

	_videoDriver->setRenderTarget(renderTargets, true, true);*/
	//_videoDriver->draw2DImage(_reflectionMap,core::position2d<s32>(0,0));
}

// returns the axis aligned bounding box of terrain
const core::aabbox3d<f32>& RealisticWaterSceneNode::getBoundingBox() const
{
	return _waterSceneNode->getBoundingBox();
}

void RealisticWaterSceneNode::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
	video::IVideoDriver* driver = services->getVideoDriver();

	core::matrix4 projection = driver->getTransform(video::ETS_PROJECTION);
	core::matrix4 view = driver->getTransform(video::ETS_VIEW);
	core::matrix4 world = driver->getTransform(video::ETS_WORLD);

	core::matrix4 cameraView = _camera->getViewMatrix();

	//vertex shader constants
	//services->setVertexShaderConstant("View", view.pointer(), 16);

	core::matrix4 worldViewProj = projection;
	worldViewProj *= view;
	worldViewProj *= world;

	core::matrix4 worldReflectionViewProj = projection;
	worldReflectionViewProj *= cameraView;
	worldReflectionViewProj *= world;

	f32 waveLength = 0.1f;
	f32 time = _time / 100000.0f;
	core::vector3df cameraPosition = _sceneManager->getActiveCamera()->getPosition();

#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR == 9)
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldViewProj"), worldViewProj.pointer(), 16);
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldReflectionViewProj"), worldReflectionViewProj.pointer(), 16);
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WaveLength"), &waveLength, 1);
	services->setVertexShaderConstant(services->getVertexShaderConstantID("Time"), &time, 1);
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WindForce"), &_windForce, 1);
	services->setVertexShaderConstant(services->getVertexShaderConstantID("WindDirection"), &_windDirection.X, 2);
	services->setPixelShaderConstant(services->getVertexShaderConstantID("CameraPosition"), &cameraPosition.X, 3);
	services->setPixelShaderConstant(services->getVertexShaderConstantID("WaveHeight"), &_waveHeight, 1);
	services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterColor"), &_waterColor.r, 4);
	services->setPixelShaderConstant(services->getVertexShaderConstantID("ColorBlendFactor"), &_colorBlendFactor, 1);
#else
	services->setVertexShaderConstant("WorldViewProj", worldViewProj.pointer(), 16);
	services->setVertexShaderConstant("WorldReflectionViewProj", worldReflectionViewProj.pointer(), 16);
	services->setVertexShaderConstant("WaveLength", &waveLength, 1);
	services->setVertexShaderConstant("Time"), &time, 1);
	services->setVertexShaderConstant("WindForce", &_windForce, 1);
	services->setVertexShaderConstant("WindDirection", &_windDirection.X, 2);
	services->setPixelShaderConstant("CameraPosition", &cameraPosition.X, 3);
	services->setPixelShaderConstant("WaveHeight", &_waveHeight, 1);
	services->setPixelShaderConstant("WaterColor", &_waterColor.r, 4);
	services->setPixelShaderConstant("ColorBlendFactor", &_colorBlendFactor, 1);
#endif

	//texture constants for GLSL
	if (driver->getDriverType() == video::EDT_OPENGL)
	{
		int var0 = 0;
		int var1 = 1;
		int var2 = 2;

#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR == 9)
		services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterBump"), &var0, 1);
		services->setPixelShaderConstant(services->getVertexShaderConstantID("RefractionMap"), &var1, 1);
		services->setPixelShaderConstant(services->getVertexShaderConstantID("ReflectionMap"), &var2, 1);
#else
		services->setPixelShaderConstant("WaterBump", &var0, 1);
		services->setPixelShaderConstant("RefractionMap", &var1, 1);
		services->setPixelShaderConstant("ReflectionMap", &var2, 1);
#endif
	}
}

void RealisticWaterSceneNode::setWindForce(const f32 windForce)
{
	_windForce = windForce;
}

void RealisticWaterSceneNode::setWindDirection(const core::vector2df& windDirection)
{
	_windDirection = windDirection;
	_windDirection.normalize();
}

void RealisticWaterSceneNode::setWaveHeight(const f32 waveHeight)
{
	_waveHeight = waveHeight;
}

void RealisticWaterSceneNode::setWaterColor(const video::SColorf& waterColor)
{
	_waterColor = waterColor;
}

void RealisticWaterSceneNode::setColorBlendFactor(const f32 colorBlendFactor)
{
	_colorBlendFactor = colorBlendFactor;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_DBN_LAYERS_HPP
#define DLL_DBN_LAYERS_HPP

#include "tmp.hpp"

namespace dll {

namespace detail {

template<typename... Layers>
struct is_dynamic : cpp::or_u<layer_traits<Layers>::is_dynamic()...> {};

template<typename... Layers>
struct is_convolutional : cpp::or_u<layer_traits<Layers>::is_convolutional_rbm_layer()...> {};

template<typename... Layers>
struct is_multiplex : cpp::or_u<layer_traits<Layers>::is_multiplex_layer()...> {};

// TODO validate_layer_pair should be made more robust when
// transform layer are present between layers

template<typename L1, typename L2, typename Enable = void>
struct validate_layer_pair;

template<typename L1, typename L2>
struct validate_layer_pair <L1, L2, std::enable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>>
    : std::true_type {};

template<typename L1, typename L2>
struct validate_layer_pair <L1, L2, cpp::disable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>> : cpp::bool_constant<layer_traits<L1>::output_size() == layer_traits<L2>::input_size()> {};

template<typename... Layers>
struct validate_layers_impl;

template<typename Layer>
struct validate_layers_impl <Layer> : std::true_type {};

template<typename L1, typename L2, typename... Layers>
struct validate_layers_impl <L1, L2, Layers...> :
    cpp::bool_constant_c<
        cpp::and_u<
            validate_layer_pair<L1, L2>::value,
            validate_layers_impl<L2, Layers...>::value
        >> {};

//Note: It is not possible to add a template parameter with default value (SFINAE) on a variadic struct
//therefore, implementing the traits as function is nicer than nested structures

template<typename... Layers, cpp_enable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid(){
    return true;
}

template<typename... Layers, cpp_disable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid(){
    return validate_layers_impl<Layers...>();
}

template<typename... Layers>
struct validate_label_layers;

template<typename Layer>
struct validate_label_layers <Layer> : std::true_type {};

template<typename L1, typename L2, typename... Layers>
struct validate_label_layers <L1, L2, Layers...> :
    cpp::bool_constant_c<
        cpp::and_u<
            layer_traits<L1>::output_size() <= layer_traits<L2>::input_size(),
            validate_label_layers<L2, Layers...>::value
        >> {};

} // end of namespace detail

/**
 * \brief Simple placeholder for a collection of layers
 */
template<typename... Layers>
struct dbn_layers {
    static constexpr const std::size_t layers = sizeof...(Layers);
    static constexpr const bool is_dynamic = detail::is_dynamic<Layers...>();
    static constexpr const bool is_convolutional = detail::is_convolutional<Layers...>();
    static constexpr const bool is_multiplex = detail::is_multiplex<Layers...>();

    static_assert(layers > 0, "A DBN must have at least 1 layer");
    static_assert(detail::are_layers_valid<Layers...>(), "The inner sizes of RBM must correspond");

    using tuple_type = std::tuple<Layers...>;
};

/**
 * \brief Simple placeholder for a collection of layers
 *
 * This version has to be used instead of dbn_layers when labels are placed in
 * the last layer.
 */
template<typename... Layers>
struct dbn_label_layers {
    static constexpr const std::size_t layers = sizeof...(Layers);
    static constexpr const bool is_dynamic = false;
    static constexpr const bool is_convolutional = false;   //There is no support for convolutional RBM and labels
    static constexpr const bool is_multiplex = false;       //There is no support for multiplex layers and labels

    static_assert(layers > 0, "A DBN must have at least 1 layer");
    static_assert(detail::validate_label_layers<Layers...>::value, "The inner sizes of RBM must correspond");
    static_assert(!detail::is_dynamic<Layers...>(), "dbn_label_layers should not be used with dynamic RBMs");

    using tuple_type = std::tuple<Layers...>;
};

} //end of namespace dll

#endif
<commit_msg>Start working on new layers implementation<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_DBN_LAYERS_HPP
#define DLL_DBN_LAYERS_HPP

#include "tmp.hpp"

namespace dll {

namespace detail {

template<typename... Layers>
struct is_dynamic : cpp::or_u<layer_traits<Layers>::is_dynamic()...> {};

template<typename... Layers>
struct is_convolutional : cpp::or_u<layer_traits<Layers>::is_convolutional_rbm_layer()...> {};

template<typename... Layers>
struct is_multiplex : cpp::or_u<layer_traits<Layers>::is_multiplex_layer()...> {};

// TODO validate_layer_pair should be made more robust when
// transform layer are present between layers

template<typename L1, typename L2, typename Enable = void>
struct validate_layer_pair;

template<typename L1, typename L2>
struct validate_layer_pair <L1, L2, std::enable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>>
    : std::true_type {};

template<typename L1, typename L2>
struct validate_layer_pair <L1, L2, cpp::disable_if_t<layer_traits<L1>::is_transform_layer() || layer_traits<L2>::is_transform_layer()>> : cpp::bool_constant<layer_traits<L1>::output_size() == layer_traits<L2>::input_size()> {};

template<typename... Layers>
struct validate_layers_impl;

template<typename Layer>
struct validate_layers_impl <Layer> : std::true_type {};

template<typename L1, typename L2, typename... Layers>
struct validate_layers_impl <L1, L2, Layers...> :
    cpp::bool_constant_c<
        cpp::and_u<
            validate_layer_pair<L1, L2>::value,
            validate_layers_impl<L2, Layers...>::value
        >> {};

//Note: It is not possible to add a template parameter with default value (SFINAE) on a variadic struct
//therefore, implementing the traits as function is nicer than nested structures

template<typename... Layers, cpp_enable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid(){
    return true;
}

template<typename... Layers, cpp_disable_if(is_dynamic<Layers...>::value)>
constexpr bool are_layers_valid(){
    return validate_layers_impl<Layers...>();
}

template<typename... Layers>
struct validate_label_layers;

template<typename Layer>
struct validate_label_layers <Layer> : std::true_type {};

template<typename L1, typename L2, typename... Layers>
struct validate_label_layers <L1, L2, Layers...> :
    cpp::bool_constant_c<
        cpp::and_u<
            layer_traits<L1>::output_size() <= layer_traits<L2>::input_size(),
            validate_label_layers<L2, Layers...>::value
        >> {};

} // end of namespace detail

/**
 * \brief Simple placeholder for a collection of layers
 */
template<typename... Layers>
struct dbn_layers {
    static constexpr const std::size_t layers = sizeof...(Layers);
    static constexpr const bool is_dynamic = detail::is_dynamic<Layers...>();
    static constexpr const bool is_convolutional = detail::is_convolutional<Layers...>();
    static constexpr const bool is_multiplex = detail::is_multiplex<Layers...>();

    static_assert(layers > 0, "A DBN must have at least 1 layer");
    static_assert(detail::are_layers_valid<Layers...>(), "The inner sizes of RBM must correspond");

    using tuple_type = std::tuple<Layers...>;
};

/**
 * \brief Simple placeholder for a collection of layers
 *
 * This version has to be used instead of dbn_layers when labels are placed in
 * the last layer.
 */
template<typename... Layers>
struct dbn_label_layers {
    static constexpr const std::size_t layers = sizeof...(Layers);
    static constexpr const bool is_dynamic = false;
    static constexpr const bool is_convolutional = false;   //There is no support for convolutional RBM and labels
    static constexpr const bool is_multiplex = false;       //There is no support for multiplex layers and labels

    static_assert(layers > 0, "A DBN must have at least 1 layer");
    static_assert(detail::validate_label_layers<Layers...>::value, "The inner sizes of RBM must correspond");
    static_assert(!detail::is_dynamic<Layers...>(), "dbn_label_layers should not be used with dynamic RBMs");

    using tuple_type = std::tuple<Layers...>;
};

namespace detail {

template<std::size_t I, typename T>
struct layers_leaf {
    T value;

    constexpr T& get() noexcept {
        return value;
    }

    constexpr const T& get() const noexcept {
        return value;
    }
};

template<typename Indices, typename... Layers>
struct layers_impl;

template<std::size_t... I, typename... Layers>
struct layers_impl <std::index_sequence<I...>, Layers...>> : layers_leaf<I, Layers>... {

};

template<typename... Layers>
struct layers {
    static constexpr const std::size_t layers = sizeof...(Layers);

    using base_t = layers_impl<std::make_index_sequence<layers>, Layers...>;

    base_t base;
}

//Note: Maybe simplify further removing the type_list

template<typename... T>
struct type_list {};

template<std::size_t I, typename T>
struct layer_type;

template<std::sizesize_t I>
struct layer_type<I, type_list<> >{
    static_assert(I == 0, "index out of range");
    static_assert(I != 0, "index out of range");
};

template<typename Head, typename... T>
struct layer_type<0, type_list<Head, T...>> {
    using type = Head;
};

template<std::size_t I, typename Head, typename ... T>
struct layer_type<I, type_list<Head,  T...>> {
    using type = typename layer_type<I-1, type_list<T...> >::type
};

template<std::size_t I, typename... T>
using layer_type_t = typename layer_type <I, type_list<T...>>::type;

} //end of namespace detail

} //end of namespace dll

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_RBM_COMMON_HPP
#define DLL_RBM_COMMON_HPP

#include "rbm_traits.hpp"

namespace dll {

namespace rbm_detail {

template<typename RBM>
void store(std::ostream& os, const RBM& rbm){
    binary_write_all(os, rbm.w);
    binary_write_all(os, rbm.b);
    binary_write_all(os, rbm.c);
}

template<typename RBM>
void load(std::istream& is, RBM& rbm){
    binary_load_all(is, rbm.w);
    binary_load_all(is, rbm.b);
    binary_load_all(is, rbm.c);
}

template<typename RBM>
void store(const std::string& file, const RBM& rbm){
    std::ofstream os(file, std::ofstream::binary);
    store(os, rbm);
}

template<typename RBM>
void load(const std::string& file, RBM& rbm){
    std::ifstream is(file, std::ifstream::binary);
    load(is, rbm);
}

template<typename Iterator, typename RBM>
void init_weights(Iterator first, Iterator last, RBM& rbm){
    auto size = std::distance(first, last);

    //Initialize the visible biases to log(pi/(1-pi))
    for(std::size_t i = 0; i < num_visible(rbm); ++i){
        auto count = std::count_if(first, last,
            [i](auto& a){return a[i] == 1; });

        auto pi = static_cast<double>(count) / size;
        pi += 0.0001;
        rbm.c(i) = log(pi / (1.0 - pi));

        cpp_assert(std::isfinite(rbm.c(i)), "NaN verify");
    }
}

template<typename RBM, typename V, typename H, cpp::enable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight energy(const RBM& rbm, const V& v, const H& h){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //E(v,h) = -sum(ai*vi) - sum(bj*hj) -sum(vi*hj*wij)

        auto mid_term = 0.0;

        //TODO Simplify that
        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            for(std::size_t j = 0; j < num_hidden(rbm); ++j){
                mid_term += rbm.w(i, j) * v(i) * h(j);
            }
        }

        return -etl::dot(rbm.c, v) - etl::dot(rbm.b, h) - mid_term;
    } else {
        return 0.0;
    }
}

template<typename RBM, typename V, typename H, cpp::disable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight energy(const RBM& rbm, const V& v, const H& h){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //E(v,h) = -sum(ai*vi) - sum(bj*hj) -sum(vi*hj*wij)

        auto visible_term = 0.0;
        auto hidden_term = 0.0;

        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            visible_term = rbm.c(i) * v[i];
        }

        for(std::size_t j = 0; j < num_hidden(rbm); ++j){
            hidden_term = rbm.b(j) * h[j];
        }

        auto mid_term = 0.0;

        //TODO Simplify that
        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            for(std::size_t j = 0; j < num_hidden(rbm); ++j){
                mid_term += rbm.w(i, j) * v(i) * h(j);
            }
        }

        return -visible_term - hidden_term - mid_term;
    } else {
        return 0.0;
    }
}

template<typename RBM, typename V, cpp::enable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight free_energy(const RBM& rbm, const V& v){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //F(v) = -sum(ai*vi) - sum(log(1 + e^(xj)))
        //xj = input to hidden neuron j

        using namespace etl;

        static fast_matrix<typename RBM::weight, 1, RBM::num_hidden> t;

        auto x = rbm.b + mmul(reshape<1, RBM::desc::num_visible>(v), rbm.w, t);

        return -dot(rbm.c, v) - sum(log(1.0 + exp(x)));
    } else {
        return 0.0;
    }
}

template<typename RBM, typename V, cpp::disable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight free_energy(const RBM& rbm, const V& v){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //F(v) = -sum(ai*vi) - sum(log(1 + e^(xj)))
        //xj = input to hidden neuron j

        auto visible_term = 0.0;

        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            visible_term = rbm.c(i) * v[i];
        }

        auto mid_term = 0.0;

        for(std::size_t j = 0; j < num_hidden(rbm); ++j){
            auto x = rbm.b(j);
            for(std::size_t i = 0; i < num_visible(rbm); ++i){
                x += v[i] * rbm.w(i,j);
            }

            mid_term += std::log(1.0 + std::exp(x));
        }

        return -visible_term - mid_term;
    } else {
        return 0.0;
    }
}

template<typename Sample, typename RBM>
void reconstruct(const Sample& items, RBM& rbm){
    cpp_assert(items.size() == num_visible(rbm), "The size of the training sample must match visible units");

    cpp::stop_watch<> watch;

    //Set the state of the visible units
    rbm.v1 = items;

    rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);
    rbm.activate_visible(rbm.h1_a, rbm.h1_s, rbm.v2_a, rbm.v2_s);
    rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

    std::cout << "Reconstruction took " << watch.elapsed() << "ms" << std::endl;
}

template<typename RBM>
void display_weights(RBM& rbm){
    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            std::cout << rbm.w(i, j) << " ";
        }
        std::cout << std::endl;
    }
}

template<typename RBM>
void display_weights(RBM& rbm, std::size_t matrix){
    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        for(std::size_t i = 0; i < num_visible(rbm);){
            for(std::size_t m = 0; m < matrix; ++m){
                std::cout << rbm.w(i++, j) << " ";
            }
            std::cout << std::endl;
        }
    }
}

template<typename RBM>
void display_visible_units(RBM& rbm){
    std::cout << "Visible  Value" << std::endl;

    for(std::size_t i = 0; i < num_visible(rbm); ++i){
        printf("%-8lu %d\n", i, rbm.v2_s(i));
    }
}

template<typename RBM>
void display_visible_units(RBM& rbm, std::size_t matrix){
    for(std::size_t i = 0; i < matrix; ++i){
        for(std::size_t j = 0; j < matrix; ++j){
            std::cout << rbm.v2_s(i * matrix + j) << " ";
        }
        std::cout << std::endl;
    }
}

template<typename RBM>
void display_hidden_units(RBM& rbm){
    std::cout << "Hidden Value" << std::endl;

    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        printf("%-8lu %d\n", j, rbm.h2_s(j));
    }
}

} //end of rbm_detail

} //end of dll namespace

#endif
<commit_msg>Cleanup after me<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_RBM_COMMON_HPP
#define DLL_RBM_COMMON_HPP

#include "rbm_traits.hpp"

namespace dll {

namespace rbm_detail {

template<typename RBM>
void store(std::ostream& os, const RBM& rbm){
    binary_write_all(os, rbm.w);
    binary_write_all(os, rbm.b);
    binary_write_all(os, rbm.c);
}

template<typename RBM>
void load(std::istream& is, RBM& rbm){
    binary_load_all(is, rbm.w);
    binary_load_all(is, rbm.b);
    binary_load_all(is, rbm.c);
}

template<typename RBM>
void store(const std::string& file, const RBM& rbm){
    std::ofstream os(file, std::ofstream::binary);
    store(os, rbm);
}

template<typename RBM>
void load(const std::string& file, RBM& rbm){
    std::ifstream is(file, std::ifstream::binary);
    load(is, rbm);
}

template<typename Iterator, typename RBM>
void init_weights(Iterator first, Iterator last, RBM& rbm){
    auto size = std::distance(first, last);

    //Initialize the visible biases to log(pi/(1-pi))
    for(std::size_t i = 0; i < num_visible(rbm); ++i){
        auto count = std::count_if(first, last,
            [i](auto& a){return a[i] == 1; });

        auto pi = static_cast<double>(count) / size;
        pi += 0.0001;
        rbm.c(i) = log(pi / (1.0 - pi));

        cpp_assert(std::isfinite(rbm.c(i)), "NaN verify");
    }
}

//Note: Considering that energy and free energy are not critical, their implementations
//are not highly optimized.

template<typename RBM, typename V, typename H, cpp::enable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight energy(const RBM& rbm, const V& v, const H& h){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //E(v,h) = -sum(ai*vi) - sum(bj*hj) -sum(vi*hj*wij)

        auto mid_term = 0.0;

        //TODO Simplify that
        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            for(std::size_t j = 0; j < num_hidden(rbm); ++j){
                mid_term += rbm.w(i, j) * v(i) * h(j);
            }
        }

        return -etl::dot(rbm.c, v) - etl::dot(rbm.b, h) - mid_term;
    } else {
        return 0.0;
    }
}

template<typename RBM, typename V, typename H, cpp::disable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight energy(const RBM& rbm, const V& v, const H& h){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        etl::dyn_vector<typename V::value_type> ev(v);
        etl::dyn_vector<typename H::value_type> eh(h);
        return energy(rbm, ev, eh);
    } else {
        return 0.0;
    }
}

//Free energy are computed from the E(v,h) formulas
//1. by isolating hi in the E(v,h) formulas
//2. by using the sum_hi which sums over all the possible values of hi
//3. by considering only binary hidden units, the values are only 0 and 1
//and therefore the values can be "integrated out" easily.

template<typename RBM, typename V, cpp::enable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight free_energy(const RBM& rbm, const V& v){
    if(RBM::desc::visible_unit == unit_type::BINARY && RBM::desc::hidden_unit == unit_type::BINARY){
        //Definition according to G. Hinton
        //F(v) = -sum(ai*vi) - sum(log(1 + e^(xj)))

        using namespace etl;

        dyn_matrix<typename RBM::weight> t(1UL, num_hidden(rbm));

        auto x = rbm.b + auto_vmmul(v, rbm.w, t);

        return -dot(rbm.c, v) - sum(log(1.0 + exp(x)));
    } else {
        return 0.0;
    }
}

template<typename RBM, typename V, cpp::disable_if_u<etl::is_etl_expr<V>::value> = cpp::detail::dummy>
typename RBM::weight free_energy(const RBM& rbm, const V& v){
    etl::dyn_vector<typename V::value_type> ev(v);
    return free_energy(rbm, ev);
}

template<typename Sample, typename RBM>
void reconstruct(const Sample& items, RBM& rbm){
    cpp_assert(items.size() == num_visible(rbm), "The size of the training sample must match visible units");

    cpp::stop_watch<> watch;

    //Set the state of the visible units
    rbm.v1 = items;

    rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);
    rbm.activate_visible(rbm.h1_a, rbm.h1_s, rbm.v2_a, rbm.v2_s);
    rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

    std::cout << "Reconstruction took " << watch.elapsed() << "ms" << std::endl;
}

template<typename RBM>
void display_weights(RBM& rbm){
    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        for(std::size_t i = 0; i < num_visible(rbm); ++i){
            std::cout << rbm.w(i, j) << " ";
        }
        std::cout << std::endl;
    }
}

template<typename RBM>
void display_weights(RBM& rbm, std::size_t matrix){
    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        for(std::size_t i = 0; i < num_visible(rbm);){
            for(std::size_t m = 0; m < matrix; ++m){
                std::cout << rbm.w(i++, j) << " ";
            }
            std::cout << std::endl;
        }
    }
}

template<typename RBM>
void display_visible_units(RBM& rbm){
    std::cout << "Visible  Value" << std::endl;

    for(std::size_t i = 0; i < num_visible(rbm); ++i){
        printf("%-8lu %d\n", i, rbm.v2_s(i));
    }
}

template<typename RBM>
void display_visible_units(RBM& rbm, std::size_t matrix){
    for(std::size_t i = 0; i < matrix; ++i){
        for(std::size_t j = 0; j < matrix; ++j){
            std::cout << rbm.v2_s(i * matrix + j) << " ";
        }
        std::cout << std::endl;
    }
}

template<typename RBM>
void display_hidden_units(RBM& rbm){
    std::cout << "Hidden Value" << std::endl;

    for(std::size_t j = 0; j < num_hidden(rbm); ++j){
        printf("%-8lu %d\n", j, rbm.h2_s(j));
    }
}

} //end of rbm_detail

} //end of dll namespace

#endif
<|endoftext|>


<commit_before>#ifndef ECL_STATIC_MAP
#define ECL_STATIC_MAP

#include <utility>
#include <type_traits>
#include <array>

#include <ecl/tree/red_black_tree.hpp>

namespace ecl
{

template<typename K, typename V, std::size_t N, typename Compare = std::less<K>>
class static_map
{
    using tree_t                 = tree::red_black_tree<K, V>;
    using tree_node_t            = typename tree_t::node_t;

public:
    using key_type               = typename tree_t::key_type;
    using mapped_type            = typename tree_t::value_type;
    using value_type             = std::pair<K, V>;
    using key_compare            = Compare;

    using const_iterator         = typename tree_t::const_iterator;
    using const_reverse_iterator = typename tree_t::const_reverse_iterator;

    template<typename... Args>
    explicit static_map (mapped_type&& def, Args&&... args) :
        m_nodes     { { std::forward<Args>(args)... } },
        m_not_found { std::forward<mapped_type>(def) }
    {
        build_tree();

        static_assert(std::is_nothrow_default_constructible<mapped_type>::value,
            "Value type should be nothrow default constructible.");
    }

    inline void build_tree()                                      const noexcept
    {
        for(std::size_t i = 0; i < N; ++i)
        {
            m_tree.insert(&m_nodes[i]);
        }
    }

    const mapped_type& operator[](const key_type& k)              const noexcept
    {
        const_iterator i = search(k);

        if(i == static_cast<const tree_t*>(&m_tree)->end())
        {
            return not_found();
        }

        return *i;
    }

    const mapped_type& operator[](key_type&& k)                   const noexcept
    {
        const_iterator i = search(k);

        if(i == static_cast<const tree_t*>(&m_tree)->end())
        {
            return not_found();
        }

        return *i;
    }

    std::size_t size()                                            const noexcept
    {
        return m_tree.count();
    }

    const V& not_found()                                          const noexcept
    {
        return m_not_found;
    }

    const_iterator begin()                                        const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->begin();
    }

    const_iterator end()                                          const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->end();
    }

    const_reverse_iterator rbegin()                               const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->rbegin();
    }

    const_reverse_iterator rend()                                 const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->rend();
    }

private:
    const_iterator search(key_type&& k)                           const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->find(
            std::forward<key_type>(k)
        );
    }

    const_iterator search(const key_type& k)                      const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->find(k);
    }

    mutable tree_t                     m_tree      {};
    mutable std::array<tree_node_t, N> m_nodes     {};

    const mapped_type                  m_not_found {};
};

template
<
      typename K
    , typename V
    , typename... Args
    , typename Compare = std::less<K>
>
constexpr inline const static_map
                       <
                             K
                           , V
                           , sizeof...(Args)
                           , Compare
                       > create_map(V&& def, Args&&... args)
{
    return static_map
           <
                 K
               , V
               , sizeof...(Args)
               , Compare
           >(std::forward<V>(def), std::forward<Args>(args)...);
}

} // namespace ecl

#endif // ECL_STATIC_MAP
<commit_msg>Static map static_assert fix.<commit_after>#ifndef ECL_STATIC_MAP
#define ECL_STATIC_MAP

#include <utility>
#include <type_traits>
#include <array>

#include <ecl/tree/red_black_tree.hpp>

namespace ecl
{

template<typename K, typename V, std::size_t N, typename Compare = std::less<K>>
class static_map
{
    using tree_t                 = tree::red_black_tree<K, V>;
    using tree_node_t            = typename tree_t::node_t;

public:
    using key_type               = typename tree_t::key_type;
    using mapped_type            = typename tree_t::value_type;
    using value_type             = std::pair<key_type, mapped_type>;
    using key_compare            = Compare;

    using const_iterator         = typename tree_t::const_iterator;
    using const_reverse_iterator = typename tree_t::const_reverse_iterator;

    template<typename... Args>
    explicit static_map (mapped_type&& def, Args&&... args) :
        m_nodes     { { std::forward<Args>(args)... } },
        m_not_found { std::forward<mapped_type>(def) }
    {
        static_assert(std::is_nothrow_default_constructible<mapped_type>::value,
            "Value type should be nothrow default constructible.");

        build_tree();
    }

    inline void build_tree()                                      const noexcept
    {
        for(std::size_t i = 0; i < N; ++i)
        {
            m_tree.insert(&m_nodes[i]);
        }
    }

    const mapped_type& operator[](const key_type& k)              const noexcept
    {
        const_iterator i = search(k);

        if(i == static_cast<const tree_t*>(&m_tree)->end())
        {
            return not_found();
        }

        return *i;
    }

    const mapped_type& operator[](key_type&& k)                   const noexcept
    {
        const_iterator i = search(k);

        if(i == static_cast<const tree_t*>(&m_tree)->end())
        {
            return not_found();
        }

        return *i;
    }

    std::size_t size()                                            const noexcept
    {
        return m_tree.count();
    }

    const V& not_found()                                          const noexcept
    {
        return m_not_found;
    }

    const_iterator begin()                                        const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->begin();
    }

    const_iterator end()                                          const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->end();
    }

    const_reverse_iterator rbegin()                               const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->rbegin();
    }

    const_reverse_iterator rend()                                 const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->rend();
    }

private:
    const_iterator search(key_type&& k)                           const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->find(
            std::forward<key_type>(k)
        );
    }

    const_iterator search(const key_type& k)                      const noexcept
    {
        return static_cast<const tree_t*>(&m_tree)->find(k);
    }

    mutable tree_t                     m_tree      {};
    mutable std::array<tree_node_t, N> m_nodes     {};

    const mapped_type                  m_not_found {};
};

template
<
      typename K
    , typename V
    , typename... Args
    , typename Compare = std::less<K>
>
constexpr inline const static_map
                       <
                             K
                           , V
                           , sizeof...(Args)
                           , Compare
                       > create_map(V&& def, Args&&... args)
{
    static_assert(std::is_nothrow_default_constructible<V>::value,
        "Value type should be nothrow default constructible.");

    return static_map
           <
                 K
               , V
               , sizeof...(Args)
               , Compare
           >(std::forward<V>(def), std::forward<Args>(args)...);
}

} // namespace ecl

#endif // ECL_STATIC_MAP
<|endoftext|>


<commit_before>#include "rank.hpp"

void aux_unrank(int n, int r, int *array, int edge) {
    if (n > edge) {
        array_swap(array[n-1], array[r % n]);
        aux_unrank(n-1, floor(r/n), array, edge);
    }
}

int *unrank(int n, int value, int k, int factor) {
    int *array = new int[n];
    int d, r, power = pow(factor, k);
    int edge = n-k;

    r = value / power;
    d = value % power;

    // Identity array
    for (int i = 0; i < n; ++i) {
        array[i] = i;
    }

    aux_unrank(n, r, array, edge);

    for (int i = n - 1; i >= edge; --i) {
        array[i] += orien_to_axis(d % factor);
        d = d / factor;
    }

    std::sort(array,array+edge);

    return array;
}

////////////////////////////////////////////////////////////////////////////////

int aux_rank(int n, int *array, int *inverse, int edge) {

    if (n == edge) {
        return 0;
    }

    int s = array[n-1];
    array_swap(array[n-1], array[inverse[n-1]]);
    array_swap(inverse[s], inverse[n-1]);

    return s + n * aux_rank(n-1, array, inverse, edge);
}

/*
 * Given a array with a k-permutation of n elements, returns an unique integer
 * for such permutation.
 *
 * For complete permutations, k must be equal to n.
 *
 * For k-permutations, it is assumed that the array contains the k elements in
 * rightmost k positions of the array. The contents of the rest are
 * irrelevant.
 */
int rank(int n, int *array, int k, int factor) {
    int *inverse;
    int *aux = new int[n];
    int value, orientation = 0;
    int edge = n-k;

    for (int i = 0; i < n; ++i) {
        aux[i] = cubie_to_pos(array[i]);
    }

    inverse = inv_array(aux, n);
    value = aux_rank(n, aux, inverse, edge);

    delete[] inverse;
    delete[] aux;

    value *= pow(factor,k);
    for (int i = n-k; i < n; ++i) {
        orientation = orientation * factor + cubie_to_orien(array[i]);
    }
    value += orientation;

    delete[] array;

    return value;
}
<commit_msg>prueba de arreglar unrank<commit_after>#include <algorithm>
#include "rank.hpp"

void aux_unrank(int n, int r, int *array, int edge) {
    if (n > edge) {
        array_swap(array[n-1], array[r % n]);
        aux_unrank(n-1, floor(r/n), array, edge);
    }
}

int *unrank(int n, int value, int k, int factor) {
    int *array = new int[n];
    int *aux = new bool[n];
    int d, r, power = pow(factor, k);
    int edge = n-k;

    r = value / power;
    d = value % power;

    // Identity array
    for (int i = 0; i < n; ++i) {
        array[i] = i;
        aux[i] = true;
    }

    aux_unrank(n, r, array, edge);

    for (int i = n - 1; i >= edge; --i) {
        array[i] += orien_to_axis(d % factor);
        d = d / factor;
    }

    // fill incrementally the unchecked part
    for (int i = 0; i < n; ++i) {
        aux[cubie_to_pos(array[i])] = false;
    }

    aux_i = 0;
    for (int i = 0; i < n; ++i) {
        if (aux[i]) {
            array[aux_i] = i;
            aux_i++;
        }
    }
    std::sort(array, array+edge);

    delete[] aux;

    return array;
}

////////////////////////////////////////////////////////////////////////////////

int aux_rank(int n, int *array, int *inverse, int edge) {

    if (n == edge) {
        return 0;
    }

    int s = array[n-1];
    array_swap(array[n-1], array[inverse[n-1]]);
    array_swap(inverse[s], inverse[n-1]);

    return s + n * aux_rank(n-1, array, inverse, edge);
}

/*
 * Given a array with a k-permutation of n elements, returns an unique integer
 * for such permutation.
 *
 * For complete permutations, k must be equal to n.
 *
 * For k-permutations, it is assumed that the array contains the k elements in
 * rightmost k positions of the array. The contents of the rest are
 * irrelevant.
 */
int rank(int n, int *array, int k, int factor) {
    int *inverse;
    int *aux = new int[n];
    int value, orientation = 0;
    int edge = n-k;

    for (int i = 0; i < n; ++i) {
        aux[i] = cubie_to_pos(array[i]);
    }

    inverse = inv_array(aux, n);
    value = aux_rank(n, aux, inverse, edge);

    delete[] inverse;
    delete[] aux;

    value *= pow(factor,k);
    for (int i = n-k; i < n; ++i) {
        orientation = orientation * factor + cubie_to_orien(array[i]);
    }
    value += orientation;

    delete[] array;

    return value;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <string>
using std::string;
#include <utility>
using std::make_pair;

#include <GPUData.hpp>
using isa::OpenCL::GPUData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <utils.hpp>
using isa::utils::toStringValue;

#ifndef MEMSET_HPP
#define MEMSET_HPP

namespace isa {

namespace OpenCL {

template < typename T > class Memset {
public:
	Memset(string dataType);
	~Memset();

	void compile(cl::Context *clContext, cl::Device *clDevice) throw (OpenCLError);
	void run(T value, GPUData< T > *memory) throw (OpenCLError);

	inline void setCLQueue(cl::CommandQueue *queue);

private:
	string dataType;
	cl::Kernel *kernel;
	cl::CommandQueue *clCommands;
};

// Implementation

template< typename T > Memset< T >::Memset(string dataType) : dataType(dataType), kernel(0), clCommands(0) {}

template< typename T > Memset< T >::~Memset() {
	if ( kernel != 0 ) {
		delete kernel;
	}
}

template< typename T > void Memset< T >::compile(cl::Context *clContext, cl::Device *clDevice) throw (OpenCLError) {

	string code = "__kernel void Memset(" + dataType + " value, __global " + dataType + " *mem) {\nmem[get_global_id(0)] = value;\n}";

	cl::Program *clProgram = 0;
	try {
		cl::Program::Sources sources(1, make_pair(code.c_str(), code.length()));
		clProgram = new cl::Program(*clContext, sources);
		clProgram->build(vector< cl::Device >(1, *clDevice));
	}
	catch ( cl::Error err ) {
		throw OpenCLError("It is not possible to build the Memset OpenCL program: " + clProgram->getBuildInfo< CL_PROGRAM_BUILD_LOG >(*clDevice) + ".");
	}

	if ( kernel != 0 ) {
		delete kernel;
	}
	try {
		kernel = new cl::Kernel(*clProgram, "Memset", NULL);
	}
	catch ( cl::Error err ) {
		string err_s = toStringValue< cl_int >(err.err());
		throw OpenCLError("It is not possible to create the kernel for Memset: " + err_s + ".");
	}
	delete clProgram;
}

template< typename T > void Memset< T >::run(T value, GPUData< T > *memory) throw (OpenCLError) {
	if ( kernel == 0 ) {
		throw OpenCLError("First generate the kernel.");
	}

	cl::NDRange globalSize(memory->getDeviceDataSize() / sizeof(T));
	kernel->setArg(0, value);
	kernel->setArg(1, *(memory->getDeviceData()));

	try {
		clCommands->enqueueNDRangeKernel(*kernel, cl::NullRange, globalSize, cl::NullRange, NULL, NULL);
	}
	catch ( cl::Error err ) {
		string err_s = toStringValue< cl_int >(err.err());
		throw OpenCLError("Impossible to run Memset: " + err_s + ".");
	}
}

template< typename T > inline void setCLQueue(cl::CommandQueue *queue) {
	clCommands = queue;
}

} // OpenCL
} // isa

#endif // MEMSET_HPP

<commit_msg>The Memset kernel is complete.<commit_after>/*
 * Copyright (C) 2011
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <string>
using std::string;
#include <utility>
using std::make_pair;

#include <GPUData.hpp>
using isa::OpenCL::GPUData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <utils.hpp>
using isa::utils::toStringValue;

#ifndef MEMSET_HPP
#define MEMSET_HPP

namespace isa {

namespace OpenCL {

template < typename T > class Memset {
public:
	Memset(string dataType);
	~Memset();

	void compile(cl::Context *clContext, cl::Device *clDevice) throw (OpenCLError);
	void run(T value, GPUData< T > *memory) throw (OpenCLError);

	inline void setCLQueue(cl::CommandQueue *queue);

private:
	string dataType;
	cl::Kernel *kernel;
	cl::CommandQueue *clCommands;
};

// Implementation

template< typename T > Memset< T >::Memset(string dataType) : dataType(dataType), kernel(0), clCommands(0) {}

template< typename T > Memset< T >::~Memset() {
	if ( kernel != 0 ) {
		delete kernel;
	}
}

template< typename T > void Memset< T >::compile(cl::Context *clContext, cl::Device *clDevice) throw (OpenCLError) {

	string code = "__kernel void Memset(" + dataType + " value, __global " + dataType + " *mem) {\nmem[get_global_id(0)] = value;\n}";

	cl::Program *clProgram = 0;
	try {
		cl::Program::Sources sources(1, make_pair(code.c_str(), code.length()));
		clProgram = new cl::Program(*clContext, sources);
		clProgram->build(vector< cl::Device >(1, *clDevice));
	}
	catch ( cl::Error err ) {
		throw OpenCLError("It is not possible to build the Memset OpenCL program: " + clProgram->getBuildInfo< CL_PROGRAM_BUILD_LOG >(*clDevice) + ".");
	}

	if ( kernel != 0 ) {
		delete kernel;
	}
	try {
		kernel = new cl::Kernel(*clProgram, "Memset", NULL);
	}
	catch ( cl::Error err ) {
		string err_s = toStringValue< cl_int >(err.err());
		throw OpenCLError("It is not possible to create the kernel for Memset: " + err_s + ".");
	}
	delete clProgram;
}

template< typename T > void Memset< T >::run(T value, GPUData< T > *memory) throw (OpenCLError) {
	if ( kernel == 0 ) {
		throw OpenCLError("First generate the kernel.");
	}

	cl::NDRange globalSize(memory->getDeviceDataSize() / sizeof(T));
	kernel->setArg(0, value);
	kernel->setArg(1, *(memory->getDeviceData()));

	try {
		clCommands->enqueueNDRangeKernel(*kernel, cl::NullRange, globalSize, cl::NullRange, NULL, NULL);
	}
	catch ( cl::Error err ) {
		string err_s = toStringValue< cl_int >(err.err());
		throw OpenCLError("Impossible to run Memset: " + err_s + ".");
	}
}

template< typename T > inline void Memset< T >::setCLQueue(cl::CommandQueue *queue) {
	clCommands = queue;
}

} // OpenCL
} // isa

#endif // MEMSET_HPP

<|endoftext|>