<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <cstdlib>
#include <cassert>
#include <stdexcept>

namespace uavcan
{

template <typename T>
class LazyConstructor
{
    unsigned char data_[sizeof(T)] __attribute__((aligned(16)));  // TODO: compiler-independent alignment
    T* ptr_;

    void failure() const
    {
#if UAVCAN_EXCEPTIONS
        throw std::logic_error(typeid(*this).name());
#else
        assert(0);
        std::abort();
#endif
    }

    void ensureConstructed() const
    {
        if (!ptr_)
            failure();
    }

    void ensureNotConstructed() const
    {
        if (ptr_)
            failure();
    }

public:
    LazyConstructor()
    : ptr_(NULL)
    { }

    LazyConstructor(const LazyConstructor<T>& rhs)
    : ptr_(NULL)
    {
        if (rhs)
            construct(*rhs);  // Invoke copy constructor
    }

    ~LazyConstructor() { destroy(); }

    LazyConstructor<T>& operator=(const LazyConstructor<T>& rhs)
    {
        destroy();
        if (rhs)
            construct(*rhs);  // Invoke copy constructor
        return *this;
    }

    bool isConstructed() const { return ptr_ != NULL; }

    operator T*() const { return ptr_; }

    const T* operator->() const { ensureConstructed(); return ptr_; }
    T*       operator->()       { ensureConstructed(); return ptr_; }

    const T& operator*() const { ensureConstructed(); return *ptr_; }
    T&       operator*()       { ensureConstructed(); return *ptr_; }

    void destroy()
    {
        if (ptr_)
            ptr_->~T();
        ptr_ = NULL;
    }

    void construct()
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T();
    }

// MAX_ARGS = 6
// TEMPLATE = '''
//     template <%s>
//     void construct(%s)
//     {
//         ensureNotConstructed();
//         ptr_ = new (static_cast<void*>(data_)) T(%s);
//     }'''
// for nargs in range(1, MAX_ARGS + 1):
//     nums = [(x + 1) for x in range(nargs)]
//     l1 = ['typename P%d' % x for x in nums]
//     l2 = ['P%d p%d' % (x, x) for x in nums]
//     l3 = ['p%d' % x for x in nums]
//     print(TEMPLATE % (', '.join(l1), ', '.join(l2), ', '.join(l3)))

    template <typename P1>
    void construct(P1 p1)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1);
    }

    template <typename P1, typename P2>
    void construct(P1 p1, P2 p2)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2);
    }

    template <typename P1, typename P2, typename P3>
    void construct(P1 p1, P2 p2, P3 p3)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3);
    }

    template <typename P1, typename P2, typename P3, typename P4>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4);
    }

    template <typename P1, typename P2, typename P3, typename P4, typename P5>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5);
    }

    template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5, p6);
    }
};

}
<commit_msg>Lazy constructor init fix<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <cstdlib>
#include <cassert>
#include <stdexcept>

namespace uavcan
{

template <typename T>
class LazyConstructor
{
    unsigned char data_[sizeof(T)] __attribute__((aligned(16)));  // TODO: compiler-independent alignment
    T* ptr_;

    void failure() const
    {
#if UAVCAN_EXCEPTIONS
        throw std::logic_error(typeid(*this).name());
#else
        assert(0);
        std::abort();
#endif
    }

    void ensureConstructed() const
    {
        if (!ptr_)
            failure();
    }

    void ensureNotConstructed() const
    {
        if (ptr_)
            failure();
    }

public:
    LazyConstructor()
    : ptr_(NULL)
    {
        std::fill(data_, data_ + sizeof(T), 0);
    }

    LazyConstructor(const LazyConstructor<T>& rhs)
    : ptr_(NULL)
    {
        std::fill(data_, data_ + sizeof(T), 0);
        if (rhs)
            construct(*rhs);  // Invoke copy constructor
    }

    ~LazyConstructor() { destroy(); }

    LazyConstructor<T>& operator=(const LazyConstructor<T>& rhs)
    {
        destroy();
        if (rhs)
            construct(*rhs);  // Invoke copy constructor
        return *this;
    }

    bool isConstructed() const { return ptr_ != NULL; }

    operator T*() const { return ptr_; }

    const T* operator->() const { ensureConstructed(); return ptr_; }
    T*       operator->()       { ensureConstructed(); return ptr_; }

    const T& operator*() const { ensureConstructed(); return *ptr_; }
    T&       operator*()       { ensureConstructed(); return *ptr_; }

    void destroy()
    {
        if (ptr_)
            ptr_->~T();
        ptr_ = NULL;
    }

    void construct()
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T();
    }

// MAX_ARGS = 6
// TEMPLATE = '''
//     template <%s>
//     void construct(%s)
//     {
//         ensureNotConstructed();
//         ptr_ = new (static_cast<void*>(data_)) T(%s);
//     }'''
// for nargs in range(1, MAX_ARGS + 1):
//     nums = [(x + 1) for x in range(nargs)]
//     l1 = ['typename P%d' % x for x in nums]
//     l2 = ['P%d p%d' % (x, x) for x in nums]
//     l3 = ['p%d' % x for x in nums]
//     print(TEMPLATE % (', '.join(l1), ', '.join(l2), ', '.join(l3)))

    template <typename P1>
    void construct(P1 p1)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1);
    }

    template <typename P1, typename P2>
    void construct(P1 p1, P2 p2)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2);
    }

    template <typename P1, typename P2, typename P3>
    void construct(P1 p1, P2 p2, P3 p3)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3);
    }

    template <typename P1, typename P2, typename P3, typename P4>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4);
    }

    template <typename P1, typename P2, typename P3, typename P4, typename P5>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5);
    }

    template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
    {
        ensureNotConstructed();
        ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5, p6);
    }
};

}
<|endoftext|>


<commit_before>#ifndef SDR_H_
#define SDR_H_

#include <vector>
#include <array>
#include <bitset>
#include <iostream>
#include <utility>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <future>
#include <thread>

namespace sdr
{

typedef std::size_t position_t;
typedef std::size_t width_t;

// this holds all of the traits for a single concept
// ie - if width is 1024, this could hold up to 1024 values between 0 and 1024
// designed to be fast to create, pass around, and as util to compress sparse data
struct concept
{
    std::vector<position_t> data;

    // for vector of positions we assume the data has already been dealt with
    concept(const std::vector<position_t> & input) : data(input)
    {}

    // otherwise we assume that is hasn't, thus we only add non zero fields
    template <width_t W> concept(const std::bitset<W> & input) : data()
    {
        for(std::size_t i=0; i < input.size(); ++i) {
            if(input[i]) {
                data.push_back(i);
            }
        }
    }

    // store [amount] largest ones from input
    template <typename T, width_t W> concept(const std::array<T, W> & input, const std::size_t amount) : data()
    {
        std::vector<position_t> idx(input.size());
        std::iota(idx.begin(), idx.end(), 0);

        std::partial_sort(idx.begin(), idx.begin() + amount, idx.end(), [&](
            const T a,
            const T b
        ) {
            return input[a] > input[b];
        });

        for(std::size_t i=0; i < amount; ++i) {
            // end if value is 0
            if(! input[idx[i]]) {
                break;
            }

            data.push_back(idx[i]);
        }
    }
};

// represents a concept in storage
// designed to be able to be quickly queried and modified
struct storage_concept
{
    // store the positions of all set bits from 0 -> width
    std::unordered_set<position_t> positions;

    storage_concept(const concept & concept) : positions(concept.data.begin(), concept.data.end())
    {}

    void fill(const concept & concept)
    {
        std::copy(concept.data.begin(), concept.data.end(), std::inserter(positions, positions.begin()));
    }

    void clear()
    {
        positions.clear();
    }

    // conversion to concept via cast
    operator concept() const
    {
        return concept(std::vector<position_t>(positions.begin(), positions.end()));
    }
};

// this is the memory bank for the sdr memory unit
template <width_t Width> struct bank
{
    // all inputs we have ever received, we store here compressed into storage
    std::vector<storage_concept> storage;

    // this holds our sets of vectors for easy comparison of different objects in storage
    std::array<std::unordered_set<position_t>, Width> bitmap;

    bank() : storage(), bitmap()
    {}

    position_t insert(const concept & concept)
    {
        storage.push_back(storage_concept(concept));

        const position_t last_pos = storage.size() - 1;

        for(position_t pos : concept.data) {
            bitmap[pos].insert(last_pos);
        }

        return last_pos;
    }

    void update(const position_t pos, const concept & concept)
    {
        storage_concept & storage_concept = storage[pos];

        for(position_t i : storage_concept.positions) {
            bitmap[i].erase(pos);
        }

        storage_concept.clear();

        storage_concept.fill(concept);

        for(position_t p : storage_concept.positions) {
            bitmap[p].insert(pos);
        }
    }

    // find amount of matching bits between two vectors
    std::size_t similarity(const position_t a, const position_t b) const
    {
        std::size_t result = 0;

        for(position_t pos : storage[a].positions) {
            result += bitmap[pos].count(b);
        }

        return result;
    }

    // find amount of matching bits between two vectors
    double weighted_similarity(const position_t a, const position_t b, const std::array<double, Width> & weights) const
    {
        double result = 0;

        for(position_t pos : storage[a].positions) {
            result += bitmap[pos].count(b) * weights[pos];
        }

        return result;
    }

    // find similarity of one object compared to the OR'd result of a list of objects
    std::size_t union_similarity(const position_t pos, const std::vector<position_t> & positions) const
    {
        std::bitset<Width> punions;

        for(const position_t ppos : positions) {
            for(const position_t spos : storage[ppos].positions) {
                punions.set(spos);
            }
        }

        std::size_t result = 0;

        for(const position_t cmp : storage[pos].positions) {
            result += punions[cmp];
        }

        return result;
    }

    // find similarity of one object compared to the OR'd result of a list of objects
    double weighted_union_similarity(const position_t pos, const std::vector<position_t> & positions, const std::array<double, Width> & weights) const
    {
        std::bitset<Width> punions;

        for(const position_t ppos : positions) {
            for(const position_t spos : storage[ppos].positions) {
                punions.set(spos);
            }
        }

        double result = 0;

        for(const position_t cmp : storage[pos].positions) {
            result += punions[cmp] * weights[cmp];
        }

        return result;
    }

    // find most similar to object at pos
    // first refers to position
    // second refers to matching number of bits
    std::vector<std::pair<position_t, std::size_t>> closest(const position_t pos, const std::size_t amount) const
    {
        std::vector<position_t> idx(storage.size());
        std::vector<unsigned>     v(storage.size());

        std::iota(idx.begin(), idx.end(), 0);

        // count matching bits for each
        for(const position_t spos : storage[pos].positions) {
            for(const position_t bpos : bitmap[spos]) {
                ++v[bpos];
            }
        }

        // we dont care about our self similarity
        v[pos] = 0;

        // if there are less than amount in storage, just return amount that exist
        const auto partial_amount = ((amount >= idx.size()) ? idx.size() : amount);

        std::partial_sort(idx.begin(), idx.begin() + partial_amount, idx.end(), [&](
            const position_t a,
            const position_t b
        ) {
            return v[a] > v[b];
        });

        // create std::pair for result
        std::vector<std::pair<position_t, std::size_t>> ret;
        ret.reserve(partial_amount);

        for(std::size_t i=0; i<partial_amount; ++i) {
            const auto m = idx[i];
            ret.push_back(std::make_pair(m, static_cast<std::size_t>(v[m])));
        }

        return ret;
    }

    std::future<std::vector<std::pair<position_t, std::size_t>>> async_closest(const position_t pos, const std::size_t amount) const
    {
        return std::async(std::launch::async, &bank<Width>::closest, this, pos, amount);
    }

    // find most similar to object at pos
    // first refers to position
    // second refers to matching number of bits
    std::vector<std::pair<position_t, double>> weighted_closest(const position_t pos, const std::size_t amount, const std::array<double, Width> & weights) const
    {
        std::vector<position_t> idx(storage.size());
        std::vector<double>       v(storage.size());

        std::iota(idx.begin(), idx.end(), 0);

        // count matching bits for each
        for(const position_t spos : storage[pos].positions) {
            for(const position_t bpos : bitmap[spos]) {
                v[bpos] += weights[spos];
            }
        }

        // we dont care about our self similarity
        v[pos] = 0.0;

        // if there are less than amount in storage, just return amount that exist
        const auto partial_amount = ((amount >= idx.size()) ? idx.size() : amount);

        std::partial_sort(idx.begin(), idx.begin() + partial_amount, idx.end(), [&](
            const position_t a,
            const position_t b
        ) {
            return v[a] > v[b];
        });

        // create std::pair for result
        std::vector<std::pair<position_t, double>> ret;
        ret.reserve(partial_amount);

        for(std::size_t i=0; i<partial_amount; ++i) {
            const auto m = idx[i];
            ret.push_back(std::make_pair(m, v[m]));
        }

        return ret;
    }

    std::future<std::vector<std::pair<position_t, std::size_t>>> async_weighted_closest(const position_t pos, const std::size_t amount, const std::array<double, Width> & weights) const
    {
        return std::async(std::launch::async, &bank<Width>::weighted_closest, this, pos, amount, weights);
    }

    // return all items matching all in data
    std::vector<position_t> matching(const concept & concept) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : concept.data) {
            for(const std::size_t pos : bitmap[item]) {
                for(const std::size_t m : concept.data) {
                    if(bitmap[m].count(pos) == 0) {
                        goto skip;
                    }
                }

                matching.insert(pos);
                skip:;
            }
        }

        return std::vector<position_t>(matching.begin(), matching.end());
    }

    // has to match amount in data
    std::vector<position_t> matching(const concept & concept, const std::size_t amount) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : concept.data) {
            for(const std::size_t pos : bitmap[item]) {
                std::size_t amount_matching = 0;

                for(const std::size_t m : concept.data) {
                    amount_matching += bitmap[m].count(pos);
                }

                if(amount_matching >= amount) {
                    matching.insert(pos);
                }
            }
        }

        return std::vector<position_t>(matching.begin(), matching.end());
    }

    // has to match amount in data
    std::vector<position_t> weighted_matching(const std::vector<position_t> & data, const double amount, const std::array<double, Width> & weights) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : data) {
            for(const std::size_t pos : bitmap[item]) {
                double amount_matching = 0;

                for(const std::size_t m : data) {
                    amount_matching += bitmap[m].count(pos) * weights[m];
                }

                if(amount_matching >= amount) {
                    matching.insert(pos);
                }
            }
        }

        return std::vector<position_t>(matching.begin(), matching.end());
    }
};

} //namespace sdr

#endif
<commit_msg>use std::begin/end<commit_after>#ifndef SDR_H_
#define SDR_H_

#include <vector>
#include <array>
#include <bitset>
#include <iostream>
#include <utility>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <future>
#include <thread>

namespace sdr
{

typedef std::size_t position_t;
typedef std::size_t width_t;

// this holds all of the traits for a single concept
// ie - if width is 1024, this could hold up to 1024 values between 0 and 1024
// designed to be fast to create, pass around, and as util to compress sparse data
struct concept
{
    std::vector<position_t> data;

    // for vector of positions we assume the data has already been dealt with
    concept(const std::vector<position_t> & input) : data(input)
    {}

    // otherwise we assume that is hasn't, thus we only add non zero fields
    template <width_t W> concept(const std::bitset<W> & input) : data()
    {
        for(std::size_t i=0; i < input.size(); ++i) {
            if(input[i]) {
                data.push_back(i);
            }
        }
    }

    // store [amount] largest ones from input
    template <typename T, width_t W> concept(const std::array<T, W> & input, const std::size_t amount) : data()
    {
        std::vector<position_t> idx(input.size());
        std::iota(std::begin(idx), std::end(idx), 0);

        std::partial_sort(std::begin(idx), std::begin(idx) + amount, std::end(idx), [&](
            const T a,
            const T b
        ) {
            return input[a] > input[b];
        });

        for(std::size_t i=0; i < amount; ++i) {
            // end if value is 0
            if(! input[idx[i]]) {
                break;
            }

            data.push_back(idx[i]);
        }
    }
};

// represents a concept in storage
// designed to be able to be quickly queried and modified
struct storage_concept
{
    // store the positions of all set bits from 0 -> width
    std::unordered_set<position_t> positions;

    storage_concept(const concept & concept) : positions(std::begin(concept.data), std::end(concept.data))
    {}

    void fill(const concept & concept)
    {
        std::copy(std::begin(concept.data), std::end(concept.data), std::inserter(positions, std::begin(positions)));
    }

    void clear()
    {
        positions.clear();
    }

    // conversion to concept via cast
    operator concept() const
    {
        return concept(std::vector<position_t>(std::begin(positions), std::end(positions)));
    }
};

// this is the memory bank for the sdr memory unit
template <width_t Width> struct bank
{
    // all inputs we have ever received, we store here compressed into storage
    std::vector<storage_concept> storage;

    // this holds our sets of vectors for easy comparison of different objects in storage
    std::array<std::unordered_set<position_t>, Width> bitmap;

    bank() : storage(), bitmap()
    {}

    position_t insert(const concept & concept)
    {
        storage.push_back(storage_concept(concept));

        const position_t last_pos = storage.size() - 1;

        for(position_t pos : concept.data) {
            bitmap[pos].insert(last_pos);
        }

        return last_pos;
    }

    void update(const position_t pos, const concept & concept)
    {
        storage_concept & storage_concept = storage[pos];

        for(position_t i : storage_concept.positions) {
            bitmap[i].erase(pos);
        }

        storage_concept.clear();

        storage_concept.fill(concept);

        for(position_t p : storage_concept.positions) {
            bitmap[p].insert(pos);
        }
    }

    // find amount of matching bits between two vectors
    std::size_t similarity(const position_t a, const position_t b) const
    {
        std::size_t result = 0;

        for(position_t pos : storage[a].positions) {
            result += bitmap[pos].count(b);
        }

        return result;
    }

    // find amount of matching bits between two vectors
    double weighted_similarity(const position_t a, const position_t b, const std::array<double, Width> & weights) const
    {
        double result = 0;

        for(position_t pos : storage[a].positions) {
            result += bitmap[pos].count(b) * weights[pos];
        }

        return result;
    }

    // find similarity of one object compared to the OR'd result of a list of objects
    std::size_t union_similarity(const position_t pos, const std::vector<position_t> & positions) const
    {
        std::bitset<Width> punions;

        for(const position_t ppos : positions) {
            for(const position_t spos : storage[ppos].positions) {
                punions.set(spos);
            }
        }

        std::size_t result = 0;

        for(const position_t cmp : storage[pos].positions) {
            result += punions[cmp];
        }

        return result;
    }

    // find similarity of one object compared to the OR'd result of a list of objects
    double weighted_union_similarity(const position_t pos, const std::vector<position_t> & positions, const std::array<double, Width> & weights) const
    {
        std::bitset<Width> punions;

        for(const position_t ppos : positions) {
            for(const position_t spos : storage[ppos].positions) {
                punions.set(spos);
            }
        }

        double result = 0;

        for(const position_t cmp : storage[pos].positions) {
            result += punions[cmp] * weights[cmp];
        }

        return result;
    }

    // find most similar to object at pos
    // first refers to position
    // second refers to matching number of bits
    std::vector<std::pair<position_t, std::size_t>> closest(const position_t pos, const std::size_t amount) const
    {
        std::vector<position_t> idx(storage.size());
        std::vector<unsigned>     v(storage.size());

        std::iota(std::begin(idx), std::end(idx), 0);

        // count matching bits for each
        for(const position_t spos : storage[pos].positions) {
            for(const position_t bpos : bitmap[spos]) {
                ++v[bpos];
            }
        }

        // we dont care about our self similarity
        v[pos] = 0;

        // if there are less than amount in storage, just return amount that exist
        const auto partial_amount = ((amount >= idx.size()) ? idx.size() : amount);

        std::partial_sort(std::begin(idx), std::begin(idx) + partial_amount, std::end(idx), [&](
            const position_t a,
            const position_t b
        ) {
            return v[a] > v[b];
        });

        // create std::pair for result
        std::vector<std::pair<position_t, std::size_t>> ret;
        ret.reserve(partial_amount);

        for(std::size_t i=0; i<partial_amount; ++i) {
            const auto m = idx[i];
            ret.push_back(std::make_pair(m, static_cast<std::size_t>(v[m])));
        }

        return ret;
    }

    std::future<std::vector<std::pair<position_t, std::size_t>>> async_closest(const position_t pos, const std::size_t amount) const
    {
        return std::async(std::launch::async, &bank<Width>::closest, this, pos, amount);
    }

    // find most similar to object at pos
    // first refers to position
    // second refers to matching number of bits
    std::vector<std::pair<position_t, double>> weighted_closest(const position_t pos, const std::size_t amount, const std::array<double, Width> & weights) const
    {
        std::vector<position_t> idx(storage.size());
        std::vector<double>       v(storage.size());

        std::iota(std::begin(idx), std::end(idx), 0);

        // count matching bits for each
        for(const position_t spos : storage[pos].positions) {
            for(const position_t bpos : bitmap[spos]) {
                v[bpos] += weights[spos];
            }
        }

        // we dont care about our self similarity
        v[pos] = 0.0;

        // if there are less than amount in storage, just return amount that exist
        const auto partial_amount = ((amount >= idx.size()) ? idx.size() : amount);

        std::partial_sort(std::begin(idx), std::begin(idx) + partial_amount, std::end(idx), [&](
            const position_t a,
            const position_t b
        ) {
            return v[a] > v[b];
        });

        // create std::pair for result
        std::vector<std::pair<position_t, double>> ret;
        ret.reserve(partial_amount);

        for(std::size_t i=0; i<partial_amount; ++i) {
            const auto m = idx[i];
            ret.push_back(std::make_pair(m, v[m]));
        }

        return ret;
    }

    std::future<std::vector<std::pair<position_t, std::size_t>>> async_weighted_closest(const position_t pos, const std::size_t amount, const std::array<double, Width> & weights) const
    {
        return std::async(std::launch::async, &bank<Width>::weighted_closest, this, pos, amount, weights);
    }

    // return all items matching all in data
    std::vector<position_t> matching(const concept & concept) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : concept.data) {
            for(const std::size_t pos : bitmap[item]) {
                for(const std::size_t m : concept.data) {
                    if(bitmap[m].count(pos) == 0) {
                        goto skip;
                    }
                }

                matching.insert(pos);
                skip:;
            }
        }

        return std::vector<position_t>(std::begin(matching), std::end(matching));
    }

    // has to match amount in data
    std::vector<position_t> matching(const concept & concept, const std::size_t amount) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : concept.data) {
            for(const std::size_t pos : bitmap[item]) {
                std::size_t amount_matching = 0;

                for(const std::size_t m : concept.data) {
                    amount_matching += bitmap[m].count(pos);
                }

                if(amount_matching >= amount) {
                    matching.insert(pos);
                }
            }
        }

        return std::vector<position_t>(std::begin(matching), std::begin(matching));
    }

    // has to match amount in data
    std::vector<position_t> weighted_matching(const std::vector<position_t> & data, const double amount, const std::array<double, Width> & weights) const
    {
        std::unordered_set<position_t> matching;

        for(const std::size_t item : data) {
            for(const std::size_t pos : bitmap[item]) {
                double amount_matching = 0;

                for(const std::size_t m : data) {
                    amount_matching += bitmap[m].count(pos) * weights[m];
                }

                if(amount_matching >= amount) {
                    matching.insert(pos);
                }
            }
        }

        return std::vector<position_t>(std::begin(matching), std::end(matching));
    }
};

} //namespace sdr

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/

#include <cstdio>
#include <clocale>

#include "test.hh"

namespace pegtl
{
   struct file_content : seq< pegtl_string_t( "dummy content" ), eol, discard > {};
   struct file_grammar : seq< rep_min_max< 11, 11, file_content >, eof > {};

   void unit_test()
   {
      TEST_ASSERT( parse_stdin< file_grammar >( 16 ) );
   }

} // namespace pegtl

#include "main.hh"
<commit_msg>Remove<commit_after><|endoftext|>


<commit_before>
#include <SpikeHwIndication.h>
#include <SpikeHwRequest.h>
#include "dmaManager.h"
#include "spikehw.h"

int verbose = 0;

class SpikeHwIndication : public SpikeHwIndicationWrapper
{
  sem_t sem;
public:
    uint32_t buf[16];

  void irqChanged( const uint8_t irqLevel, const uint8_t intrSources ) {
      fprintf(stderr, "irqLevel %d intr sources %x\n", irqLevel, intrSources);
    }
    virtual void resetDone() {
	fprintf(stderr, "reset done\n");
	sem_post(&sem);
    }
    virtual void status ( const uint8_t mmcm_locked, const uint8_t irq, const uint8_t intrSources ) {
	fprintf(stderr, "axi eth status mmcm_locked=%d irq=%d intr sources=%x\n", mmcm_locked, irq, intrSources);
	sem_post(&sem);
    }

    void wait() {
	sem_wait(&sem);
    }

    void readDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeDone (  ) {
	if (verbose) fprintf(stderr, "writeDone\n");
	sem_post(&sem);
    }

    void readFlashDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readFlashDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeFlashDone (  ) {
	if (verbose) fprintf(stderr, "writeFlashDone\n");
	sem_post(&sem);
    }

    SpikeHwIndication(unsigned int id) : SpikeHwIndicationWrapper(id) {
      sem_init(&sem, 0, 0);
    }
};

SpikeHwRequestProxy *request;
SpikeHwIndication *indication;

#ifdef STANDALONE
int main(int argc, const char **argv)
{
    request = new SpikeHwRequestProxy(IfcNames_SpikeHwRequestS2H);
    indication = new SpikeHwIndication(IfcNames_SpikeHwIndicationH2S);
    fprintf(stderr, "Reading ID register\n");
    request->read((1<<18) + 0x4f8);
    indication->wait();
    for (int i = 0; i < 16; i++) {
      fprintf(stderr, "register %04x\n", i*4);
      request->read((1<<18) + i*4);
      indication->wait();
      fprintf(stderr, "now writing ...\n");
      request->write((1<<18) + i*4, 0xbeef);
      indication->wait();
      request->read((1<<18) + i*4);
      indication->wait();
    }
    return 0;
}

#else
SpikeHw::SpikeHw()
    : request(0), indication(0), dmaManager(0), didReset(false)
{
    request = new SpikeHwRequestProxy(IfcNames_SpikeHwRequestS2H);
    indication = new SpikeHwIndication(IfcNames_SpikeHwIndicationH2S);
    dmaManager = platformInit();
}

SpikeHw::~SpikeHw()
{
  //delete request;
  //delete indication;
  request = 0;
  indication = 0;
}

void SpikeHw::maybeReset()
{
    if (0)
    if (!didReset) {
	fprintf(stderr, "resetting flash\n");
	request->reset();
	indication->wait();
	//request->setParameters(50, 0);
	fprintf(stderr, "done resetting flash\n");
	didReset = true;
    }
}

void SpikeHw::status()
{
    request->status();
    indication->wait();
}

void SpikeHw::setupDma(uint32_t memfd)
{
    int memref = dmaManager->reference(memfd);
    request->setupDma(memref);
}

void SpikeHw::read(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx\n", offset);
    request->read(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::write(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (1 || verbose) fprintf(stderr, "SpikeHw::write offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->write(offset, *(uint32_t *)buf);
    indication->wait();
    request->status();
    indication->wait();
}

void SpikeHw::setFlashParameters(unsigned long cycles)
{
    request->setFlashParameters(cycles);
}

void SpikeHw::readFlash(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx\n", offset);
    request->readFlash(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::writeFlash(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (1 || verbose) fprintf(stderr, "SpikeHw::writeFlash offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->writeFlash(offset, *(uint32_t *)buf);
    indication->wait();
}
#endif
<commit_msg>removed STANDALONE from spikehw.cpp<commit_after>
#include <SpikeHwIndication.h>
#include <SpikeHwRequest.h>
#include "dmaManager.h"
#include "spikehw.h"

int verbose = 0;

class SpikeHwIndication : public SpikeHwIndicationWrapper
{
  sem_t sem;
public:
    uint32_t buf[16];

  void irqChanged( const uint8_t irqLevel, const uint8_t intrSources ) {
      fprintf(stderr, "irqLevel %d intr sources %x\n", irqLevel, intrSources);
    }
    virtual void resetDone() {
	fprintf(stderr, "reset done\n");
	sem_post(&sem);
    }
    virtual void status ( const uint8_t mmcm_locked, const uint8_t irq, const uint8_t intrSources ) {
	fprintf(stderr, "axi eth status mmcm_locked=%d irq=%d intr sources=%x\n", mmcm_locked, irq, intrSources);
	sem_post(&sem);
    }

    void wait() {
	sem_wait(&sem);
    }

    void readDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeDone (  ) {
	if (verbose) fprintf(stderr, "writeDone\n");
	sem_post(&sem);
    }

    void readFlashDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readFlashDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeFlashDone (  ) {
	if (verbose) fprintf(stderr, "writeFlashDone\n");
	sem_post(&sem);
    }

    SpikeHwIndication(unsigned int id) : SpikeHwIndicationWrapper(id) {
      sem_init(&sem, 0, 0);
    }
};

SpikeHwRequestProxy *request;
SpikeHwIndication *indication;

SpikeHw::SpikeHw()
    : request(0), indication(0), dmaManager(0), didReset(false)
{
    request = new SpikeHwRequestProxy(IfcNames_SpikeHwRequestS2H);
    indication = new SpikeHwIndication(IfcNames_SpikeHwIndicationH2S);
    dmaManager = platformInit();
}

SpikeHw::~SpikeHw()
{
  //delete request;
  //delete indication;
  request = 0;
  indication = 0;
}

void SpikeHw::maybeReset()
{
    if (0)
    if (!didReset) {
	fprintf(stderr, "resetting flash\n");
	request->reset();
	indication->wait();
	//request->setParameters(50, 0);
	fprintf(stderr, "done resetting flash\n");
	didReset = true;
    }
}

void SpikeHw::status()
{
    request->status();
    indication->wait();
}

void SpikeHw::setupDma(uint32_t memfd)
{
    int memref = dmaManager->reference(memfd);
    request->setupDma(memref);
}

void SpikeHw::read(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx\n", offset);
    request->read(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::write(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (1 || verbose) fprintf(stderr, "SpikeHw::write offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->write(offset, *(uint32_t *)buf);
    indication->wait();
    request->status();
    indication->wait();
}

void SpikeHw::setFlashParameters(unsigned long cycles)
{
    request->setFlashParameters(cycles);
}

void SpikeHw::readFlash(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx\n", offset);
    request->readFlash(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::writeFlash(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (1 || verbose) fprintf(stderr, "SpikeHw::writeFlash offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->writeFlash(offset, *(uint32_t *)buf);
    indication->wait();
}
<|endoftext|>


<commit_before>/*
 * Tests for the next hop computation (LFDB).
 *
 * Copyright (C) 2018 Vincenzo Maffione
 * Author: Vincenzo Maffione <v.maffione@gmail.com>
 *
 * This file is part of rlite.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */
#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <cassert>
#include <chrono>
#include <unistd.h>
#include <cmath>

#include "uipcp-normal-lfdb.hpp"

/* A type to represent a single routing table, excluding the default next
 * hop. */
using NextHops = std::unordered_map<rlite::NodeId, std::vector<rlite::NodeId>>;

/* A type to represent a collection of routing tables, one for each node
 * in a network. */
using RoutingTables =
    std::unordered_map<rlite::NodeId, std::pair<NextHops, rlite::NodeId>>;

/* Representation of a list of reachability tests. See the description
 * below. */
using ReachabilityTests = std::vector<std::pair<int, int>>;

struct TestLFDB : public rlite::LFDB {
    using LinksList = std::vector<std::pair<int, int>>;
    LinksList links;

    /* Populate rlite::LFDB::db from the list of links coming from
     * the test vector. */
    TestLFDB(const LinksList &links, bool lfa_enabled)
        : rlite::LFDB(lfa_enabled, /*verbose=*/false), links(links)
    {
        for (const auto &link : links) {
            gpb::LowerFlow lf1, lf2;

            lf1.set_local_node(std::to_string(link.first));
            lf1.set_remote_node(std::to_string(link.second));
            lf2.set_local_node(std::to_string(link.second));
            lf2.set_remote_node(std::to_string(link.first));
            lf1.set_cost(1);
            lf2.set_cost(1);
            lf1.set_seqnum(1);
            lf2.set_seqnum(1);
            lf1.set_state(true);
            lf2.set_state(true);
            lf1.set_age(0);
            lf2.set_age(0);

            db[lf1.local_node()][lf1.remote_node()] = lf1;
            db[lf2.local_node()][lf2.remote_node()] = lf2;
        }
    }
};

/* Returns true if the routing tables are able to route a packet from
 * 'src_node' to 'dst_node' with exactly 'n' hops. */
static bool
reachable(const RoutingTables &rtables, int src_node, int dst_node,
          int expected_nhops, const bool verbose)
{
    rlite::NodeId dst = std::to_string(dst_node);
    rlite::NodeId cur = std::to_string(src_node);

    if (verbose) {
        std::cout << "---> Start from node " << cur << std::endl;
    }
    for (; expected_nhops >= 0 && cur != dst; expected_nhops--) {
        const auto &rt                 = rtables.at(cur);
        NextHops::const_iterator nhops = rt.first.find(dst);

        if (nhops != rt.first.end()) {
            /* Entry find in the routing table. */
            cur = nhops->second.front();
        } else {
            /* Not found, use default next hop. */
            cur = rt.second;
        }
        if (verbose) {
            std::cout << "     hop to " << cur << std::endl;
        }
    }
    return cur == dst && expected_nhops == 0;
}

int
main(int argc, char **argv)
{
    auto usage = []() {
        std::cout << "lfdb-test -n SIZE\n"
                     "          -v be verbose\n"
                     "          -h show this help and exit\n";
    };
    int verbosity = 0;
    int n         = 100;
    int opt;

    while ((opt = getopt(argc, argv, "hvn:")) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;

        case 'v':
            verbosity++;
            break;

        case 'n':
            n = std::atoi(optarg);
            break;

        default:
            std::cout << "    Unrecognized option " << static_cast<char>(opt)
                      << std::endl;
            usage();
            return -1;
        }
    }

    /* Test vectors are stored in a list of pairs. Each pair is made of a list
     * of links and a list of reachability tests. A list of links describes
     * a network graph, where nodes are integer numbers; each link in the list
     * is a pair of integers, which represents a link between two nodes. An
     * item in list of reachability tests is a pair of integers; the first
     * integer refers to a destination node to be reached (from node 0), and
     * the second integer refers to the number of expected hops to reach the
     * destination node. */
    std::list<std::pair<TestLFDB::LinksList, ReachabilityTests>> test_vectors =
        {{/*links=*/{{0, 1}, {0, 3}, {1, 2}, {2, 3}},
          /*reachability_tests=*/{{1, 1}, {2, 2}, {3, 1}}}};

    {
        /* Generate a grid-shaped network of size 'sqn' x 'sqn'. */
        TestLFDB::LinksList links;
        ReachabilityTests reachability_tests;
        int sqn = static_cast<int>(std::sqrt(n));

        if (sqn < 2) {
            sqn = 2;
        }

        auto coord = [sqn](int i, int j) { return i * sqn + j; };

        for (int i = 0; i < sqn; i++) {
            for (int j = 0; j < sqn - 1; j++) {
                links.push_back({coord(i, j), coord(i, j + 1)});
                links.push_back({coord(j, i), coord(j + 1, i)});
            }
        }

        /* Get from node 0 (top left) to top right in sqn-1 steps. */
        reachability_tests.push_back({coord(0, sqn - 1), sqn - 1});

        /* Get from node 0 (top left) to bottom left in sqn-1 steps. */
        reachability_tests.push_back({coord(sqn - 1, 0), sqn - 1});

        /* Get from node 0 (top left) to bottom right. */
        reachability_tests.push_back({coord(sqn - 1, sqn - 1), 2 * (sqn - 1)});

        /* Get from node 0 (top left) to one very close to the the
         * bottom left node. */
        reachability_tests.push_back({coord(sqn - 2, 1), sqn - 1});

        test_vectors.push_back(
            make_pair(std::move(links), std::move(reachability_tests)));
    }

    int counter = 1;
    for (const auto &p : test_vectors) {
        TestLFDB::LinksList links            = p.first;
        ReachabilityTests reachability_tests = p.second;

        std::cout << "Test vector #" << counter << std::endl;

        /* Build the lfdb object under test by populating it with the
         * links in the test vector. */
        TestLFDB lfdb(links, /*lfa_enabled=*/false);

        if (verbosity >= 2) {
            std::stringstream ss;
            lfdb.dump(ss);
            std::cout << ss.str();
        }
        assert(!links.empty());

        /* Compute the routing tables for each node in the network and
         * store them into 'rtables'. */
        RoutingTables rtables;
        auto start = std::chrono::system_clock::now();

        for (const auto &kv : lfdb.db) {
            const rlite::NodeId &source = kv.first;

            lfdb.compute_next_hops(source);
            if (verbosity >= 2) {
                std::stringstream ss;
                lfdb.dump_routing(ss, source);
                std::cout << ss.str();
            }
            rtables[source] =
                make_pair(std::move(lfdb.next_hops), std::move(lfdb.dflt_nhop));
        }
        auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now() - start);

        /* Use 'rtables' to carry out all the reachability tests defined for
         * this network. */
        for (const auto &rtest : reachability_tests) {
            const int src_node = 0;
            if (!reachable(rtables, /*src_node=*/src_node,
                           /*dst_node=*/rtest.first,
                           /*expected_nhops=*/rtest.second,
                           /*verbose=*/verbosity >= 1)) {
                std::cerr << "Cannot reach node " << rtest.first
                          << " from node " << src_node << " in " << rtest.second
                          << " steps" << std::endl;
                std::cout << "Test # " << counter << " failed" << std::endl;
                return -1;
            }
        }

        std::cout << "Test # " << counter << " completed in " << delta.count()
                  << " ms" << std::endl;
        counter++;
    }

    return 0;
}
<commit_msg>uipcps: lfdb-test: add a 9-nodes handcrafted network<commit_after>/*
 * Tests for the next hop computation (LFDB).
 *
 * Copyright (C) 2018 Vincenzo Maffione
 * Author: Vincenzo Maffione <v.maffione@gmail.com>
 *
 * This file is part of rlite.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */
#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <cassert>
#include <chrono>
#include <unistd.h>
#include <cmath>

#include "uipcp-normal-lfdb.hpp"

/* A type to represent a single routing table, excluding the default next
 * hop. */
using NextHops = std::unordered_map<rlite::NodeId, std::vector<rlite::NodeId>>;

/* A type to represent a collection of routing tables, one for each node
 * in a network. */
using RoutingTables =
    std::unordered_map<rlite::NodeId, std::pair<NextHops, rlite::NodeId>>;

/* Representation of a list of reachability tests. See the description
 * below. */
using ReachabilityTests = std::vector<std::pair<int, int>>;

struct TestLFDB : public rlite::LFDB {
    using LinksList = std::vector<std::pair<int, int>>;
    LinksList links;

    /* Populate rlite::LFDB::db from the list of links coming from
     * the test vector. */
    TestLFDB(const LinksList &links, bool lfa_enabled)
        : rlite::LFDB(lfa_enabled, /*verbose=*/false), links(links)
    {
        for (const auto &link : links) {
            gpb::LowerFlow lf1, lf2;

            lf1.set_local_node(std::to_string(link.first));
            lf1.set_remote_node(std::to_string(link.second));
            lf2.set_local_node(std::to_string(link.second));
            lf2.set_remote_node(std::to_string(link.first));
            lf1.set_cost(1);
            lf2.set_cost(1);
            lf1.set_seqnum(1);
            lf2.set_seqnum(1);
            lf1.set_state(true);
            lf2.set_state(true);
            lf1.set_age(0);
            lf2.set_age(0);

            db[lf1.local_node()][lf1.remote_node()] = lf1;
            db[lf2.local_node()][lf2.remote_node()] = lf2;
        }
    }
};

/* Returns true if the routing tables are able to route a packet from
 * 'src_node' to 'dst_node' with exactly 'n' hops. */
static bool
reachable(const RoutingTables &rtables, int src_node, int dst_node,
          int expected_nhops, const bool verbose)
{
    rlite::NodeId dst = std::to_string(dst_node);
    rlite::NodeId cur = std::to_string(src_node);

    if (verbose) {
        std::cout << "---> Start from node " << cur << std::endl;
    }
    for (; expected_nhops >= 0 && cur != dst; expected_nhops--) {
        const auto &rt                 = rtables.at(cur);
        NextHops::const_iterator nhops = rt.first.find(dst);

        if (nhops != rt.first.end()) {
            /* Entry find in the routing table. */
            cur = nhops->second.front();
        } else {
            /* Not found, use default next hop. */
            cur = rt.second;
        }
        if (verbose) {
            std::cout << "     hop to " << cur << std::endl;
        }
    }
    return cur == dst && expected_nhops == 0;
}

int
main(int argc, char **argv)
{
    auto usage = []() {
        std::cout << "lfdb-test -n SIZE\n"
                     "          -v be verbose\n"
                     "          -h show this help and exit\n";
    };
    int verbosity = 0;
    int n         = 100;
    int opt;

    while ((opt = getopt(argc, argv, "hvn:")) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;

        case 'v':
            verbosity++;
            break;

        case 'n':
            n = std::atoi(optarg);
            break;

        default:
            std::cout << "    Unrecognized option " << static_cast<char>(opt)
                      << std::endl;
            usage();
            return -1;
        }
    }

    /* Test vectors are stored in a list of pairs. Each pair is made of a list
     * of links and a list of reachability tests. A list of links describes
     * a network graph, where nodes are integer numbers; each link in the list
     * is a pair of integers, which represents a link between two nodes. An
     * item in list of reachability tests is a pair of integers; the first
     * integer refers to a destination node to be reached (from node 0), and
     * the second integer refers to the number of expected hops to reach the
     * destination node. */
    std::list<std::pair<TestLFDB::LinksList, ReachabilityTests>> test_vectors =
        {{/*links=*/{{0, 1}, {0, 3}, {1, 2}, {2, 3}},
          /*reachability_tests=*/{{1, 1}, {2, 2}, {3, 1}}},
         {/*links=*/{{0, 1},
                     {0, 2},
                     {0, 3},
                     {1, 4},
                     {2, 3},
                     {2, 5},
                     {3, 4},
                     {3, 5},
                     {4, 5},
                     {4, 6},
                     {4, 7},
                     {5, 6},
                     {6, 7},
                     {7, 8}},
          /*reachability_tests=*/{
              {1, 1}, {2, 1}, {3, 1}, {4, 2}, {5, 2}, {6, 3}, {7, 3}, {8, 4}}}};

    {
        /* Generate a grid-shaped network of size 'sqn' x 'sqn'. */
        TestLFDB::LinksList links;
        ReachabilityTests reachability_tests;
        int sqn = static_cast<int>(std::sqrt(n));

        if (sqn < 2) {
            sqn = 2;
        }

        auto coord = [sqn](int i, int j) { return i * sqn + j; };

        for (int i = 0; i < sqn; i++) {
            for (int j = 0; j < sqn - 1; j++) {
                links.push_back({coord(i, j), coord(i, j + 1)});
                links.push_back({coord(j, i), coord(j + 1, i)});
            }
        }

        /* Get from node 0 (top left) to top right in sqn-1 steps. */
        reachability_tests.push_back({coord(0, sqn - 1), sqn - 1});

        /* Get from node 0 (top left) to bottom left in sqn-1 steps. */
        reachability_tests.push_back({coord(sqn - 1, 0), sqn - 1});

        /* Get from node 0 (top left) to bottom right. */
        reachability_tests.push_back({coord(sqn - 1, sqn - 1), 2 * (sqn - 1)});

        /* Get from node 0 (top left) to one very close to the the
         * bottom left node. */
        reachability_tests.push_back({coord(sqn - 2, 1), sqn - 1});

        test_vectors.push_back(
            make_pair(std::move(links), std::move(reachability_tests)));
    }

    int counter = 1;
    for (const auto &p : test_vectors) {
        TestLFDB::LinksList links            = p.first;
        ReachabilityTests reachability_tests = p.second;

        std::cout << "Test vector #" << counter << std::endl;

        /* Build the lfdb object under test by populating it with the
         * links in the test vector. */
        TestLFDB lfdb(links, /*lfa_enabled=*/false);

        if (verbosity >= 2) {
            std::stringstream ss;
            lfdb.dump(ss);
            std::cout << ss.str();
        }
        assert(!links.empty());

        /* Compute the routing tables for each node in the network and
         * store them into 'rtables'. */
        RoutingTables rtables;
        auto start = std::chrono::system_clock::now();

        for (const auto &kv : lfdb.db) {
            const rlite::NodeId &source = kv.first;

            lfdb.compute_next_hops(source);
            if (verbosity >= 2) {
                std::stringstream ss;
                lfdb.dump_routing(ss, source);
                std::cout << ss.str();
            }
            rtables[source] =
                make_pair(std::move(lfdb.next_hops), std::move(lfdb.dflt_nhop));
        }
        auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::system_clock::now() - start);

        /* Use 'rtables' to carry out all the reachability tests defined for
         * this network. */
        for (const auto &rtest : reachability_tests) {
            const int src_node = 0;
            if (!reachable(rtables, /*src_node=*/src_node,
                           /*dst_node=*/rtest.first,
                           /*expected_nhops=*/rtest.second,
                           /*verbose=*/verbosity >= 1)) {
                std::cerr << "Cannot reach node " << rtest.first
                          << " from node " << src_node << " in " << rtest.second
                          << " steps" << std::endl;
                std::cout << "Test # " << counter << " failed" << std::endl;
                return -1;
            }
        }

        std::cout << "Test # " << counter << " completed in " << delta.count()
                  << " ms" << std::endl;
        counter++;
    }

    return 0;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "processor.h"

#include <tbb/parallel_invoke.h>

#include "io_dispatcher.h"
#include "file.h"
#include "chunk.h"

using namespace upload;

tbb::task* ChunkProcessingTask::execute() {
  // Thread Safety:
  //   * Only one ChunkProcessingTask for any given Chunk at any given time
  //   * Parallel execution of more than one ChunkProcessingTask for chunks of
  //     the same File is possible

  assert (chunk_->IsInitialized());
  assert (buffer_->IsInitialized());

  // get the position from where the current input buffer needs to be processed
  const off_t internal_offset =
    std::max(off_t(0), chunk_->offset() - buffer_->base_offset());
  assert (internal_offset >= 0);
  assert (static_cast<size_t>(internal_offset) < buffer_->used_bytes());
  const unsigned char *data = buffer_->ptr() + internal_offset;

  // determine how many bytes need to be processed
  const size_t byte_count = (chunk_->size() == 0)
    ? buffer_->used_bytes() - internal_offset
    :   std::min(buffer_->base_offset()  + buffer_->used_bytes(),
                 chunk_->offset()        + chunk_->size())
      - std::max(buffer_->base_offset(), chunk_->offset());
  assert (byte_count <= buffer_->used_bytes() - internal_offset);

  // find out, if we are going to process the final block of the chunk
  const bool finalize = (
    (chunk_->size() > 0) &&
    (buffer_->base_offset() + internal_offset + byte_count
      == chunk_->offset() + chunk_->size())
  );

  // crunch the data
  Crunch(data, byte_count, finalize);

  // finalize the chunk if necessary
  if (finalize) {
    chunk_->Finalize();
  }

  // the TBB scheduler should figure out what to do next
  return NULL;
}

void ChunkProcessingTask::Crunch(const unsigned char  *data,
                                 const size_t          bytes,
                                 const bool            finalize) const {
  z_stream  &stream   = chunk_->zlib_context();
  SHA_CTX   &sha1_ctx = chunk_->sha1_context();

  const size_t max_output_size = deflateBound(&stream, bytes);
  CharBuffer *compress_buffer  = new CharBuffer(max_output_size);

  stream.avail_in  = bytes;
  stream.next_in   = const_cast<unsigned char*>(data); // sry, but zlib forces me...
  const int flush = (finalize) ? Z_FINISH : Z_NO_FLUSH;

  int retcode = -1;
  while (true) {
    stream.avail_out = compress_buffer->size();
    stream.next_out  = compress_buffer->ptr();

    retcode = deflate(&stream, flush);
    assert (retcode == Z_OK || retcode == Z_STREAM_END);

    const size_t bytes_produced = compress_buffer->size() - stream.avail_out;
    if (bytes_produced > 0) {
      compress_buffer->SetUsedBytes(bytes_produced);
      compress_buffer->SetBaseOffset(chunk_->compressed_size());
      chunk_->add_compressed_size(bytes_produced);
      const int sha_retcode = SHA1_Update(&sha1_ctx,
                                           compress_buffer->ptr(),
                                           compress_buffer->used_bytes());
      assert (sha_retcode == 1);
      chunk_->ScheduleWrite(compress_buffer);
    }

    if ((flush == Z_NO_FLUSH && retcode == Z_OK) ||
        (flush == Z_FINISH   && retcode == Z_STREAM_END)) {
      break;
    }

    if (stream.avail_out == 0) {
      compress_buffer = new CharBuffer(4096);
    }
  }

  if (finalize) {
    assert (flush == Z_FINISH);
  }
}

tbb::task* FileScrubbingTask::execute() {
  // Thread Safety:
  //   * Only one executing FileScrubbingTask per File at any time
  //   * Execution is done in-order, thus the File is processed as a stream of
  //     CharBuffers. Each CharBuffer will be processed in one FileScrubbingTask

  if (file_->MightBecomeChunked()) {
    // find chunk cut marks in the current buffer and process all chunks that
    // are fully specified (i.e. not reaching beyond the current buffer)
    const CutMarks cut_marks = FindNextChunkCutMarks();
    CutMarks::const_iterator i    = cut_marks.begin();
    CutMarks::const_iterator iend = cut_marks.end();
    for (; i != iend; ++i) {
      Chunk *fully_defined_chunk = file_->CreateNextChunk(*i);
      assert (fully_defined_chunk->IsFullyDefined());
      QueueForDeferredProcessing(fully_defined_chunk);
    }

    // if we reached the last buffer this input file will produce, all but the
    // last created chunk will be fully defined at this point
    if (IsLastBuffer()) {
      file_->FullyDefineLastChunk();
    }

    // process the current chunk, i.e. the last created chunk that potentially
    // reaches beyond the current buffer or to the end of the file
    Chunk *current_chunk = file_->current_chunk();
    if (current_chunk != NULL) {
      QueueForDeferredProcessing(current_chunk);
    }
  }

  // check if the file has a bulk chunk and continue processing it using the
  // current buffer
  if (file_->HasBulkChunk()) {
    QueueForDeferredProcessing(file_->bulk_chunk());
  }

  // wait for all scheduled chunk processing tasks on the current buffer
  SpawnTasksAndWaitForProcessing();
  reader_->ReleaseBuffer(buffer_);

  // commit the chunks that have been finished during this processing step
  CommitFinishedChunks();

  // go on with the next file buffer
  return Next();
}

void FileScrubbingTask::SpawnTasksAndWaitForProcessing() {
  tbb::task_list tasks;
  std::vector<Chunk*>::const_iterator i    = chunks_to_process_.begin();
  std::vector<Chunk*>::const_iterator iend = chunks_to_process_.end();
  for (; i != iend; ++i) {
    tbb::task *chunk_processing_task =
      new(allocate_child()) ChunkProcessingTask(*i, buffer_);
    tasks.push_back(*chunk_processing_task);
  }

  set_ref_count(chunks_to_process_.size() + 1); // +1 for the wait
  spawn_and_wait_for_all(tasks);
}

void FileScrubbingTask::CommitFinishedChunks() const {
  std::vector<Chunk*>::const_iterator i    = chunks_to_process_.begin();
  std::vector<Chunk*>::const_iterator iend = chunks_to_process_.end();
  for (; i != iend; ++i) {
    Chunk *current_chunk = *i;
    if (current_chunk->IsFullyProcessed()) {
      current_chunk->ScheduleCommit();
    }
  }

}

FileScrubbingTask::CutMarks FileScrubbingTask::FindNextChunkCutMarks() {
  const Chunk *current_chunk = file_->current_chunk();
  assert (file_->MightBecomeChunked());
  assert (current_chunk != NULL);
  assert (current_chunk->size() == 0);
  assert (current_chunk->offset() <= buffer_->base_offset());
  assert (current_chunk->offset() <  buffer_->base_offset() +
                                     static_cast<off_t>(buffer_->used_bytes()));

  CutMarks result;
  off_t next_cut;
  while ((next_cut = file_->FindNextCutMark(buffer_)) != 0) {
    result.push_back(next_cut);
  }

  return result;
}

bool FileScrubbingTask::IsLastBuffer() const {
  return file_->size() == buffer_->base_offset() + buffer_->used_bytes();
}

<commit_msg>FIX: processing of an empty buffer lead to failed assertion<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "processor.h"

#include <tbb/parallel_invoke.h>

#include "io_dispatcher.h"
#include "file.h"
#include "chunk.h"

using namespace upload;

tbb::task* ChunkProcessingTask::execute() {
  // Thread Safety:
  //   * Only one ChunkProcessingTask for any given Chunk at any given time
  //   * Parallel execution of more than one ChunkProcessingTask for chunks of
  //     the same File is possible

  assert (chunk_->IsInitialized());
  assert (buffer_->IsInitialized());

  // get the position from where the current input buffer needs to be processed
  const off_t internal_offset =
    std::max(off_t(0), chunk_->offset() - buffer_->base_offset());
  assert (internal_offset >= 0);
  assert (static_cast<size_t>(internal_offset) <= buffer_->used_bytes());
  const unsigned char *data = buffer_->ptr() + internal_offset;

  // determine how many bytes need to be processed
  const size_t byte_count = (chunk_->size() == 0)
    ? buffer_->used_bytes() - internal_offset
    :   std::min(buffer_->base_offset()  + buffer_->used_bytes(),
                 chunk_->offset()        + chunk_->size())
      - std::max(buffer_->base_offset(), chunk_->offset());
  assert (byte_count <= buffer_->used_bytes() - internal_offset);
  if (byte_count == 0) {
    return NULL;
  }

  // find out, if we are going to process the final block of the chunk
  const bool finalize = (
    (chunk_->size() > 0) &&
    (buffer_->base_offset() + internal_offset + byte_count
      == chunk_->offset() + chunk_->size())
  );

  // crunch the data
  Crunch(data, byte_count, finalize);

  // finalize the chunk if necessary
  if (finalize) {
    chunk_->Finalize();
  }

  // the TBB scheduler should figure out what to do next
  return NULL;
}

void ChunkProcessingTask::Crunch(const unsigned char  *data,
                                 const size_t          bytes,
                                 const bool            finalize) const {
  z_stream  &stream   = chunk_->zlib_context();
  SHA_CTX   &sha1_ctx = chunk_->sha1_context();

  const size_t max_output_size = deflateBound(&stream, bytes);
  CharBuffer *compress_buffer  = new CharBuffer(max_output_size);

  stream.avail_in  = bytes;
  stream.next_in   = const_cast<unsigned char*>(data); // sry, but zlib forces me...
  const int flush = (finalize) ? Z_FINISH : Z_NO_FLUSH;

  int retcode = -1;
  while (true) {
    stream.avail_out = compress_buffer->size();
    stream.next_out  = compress_buffer->ptr();

    retcode = deflate(&stream, flush);
    assert (retcode == Z_OK || retcode == Z_STREAM_END);

    const size_t bytes_produced = compress_buffer->size() - stream.avail_out;
    if (bytes_produced > 0) {
      compress_buffer->SetUsedBytes(bytes_produced);
      compress_buffer->SetBaseOffset(chunk_->compressed_size());
      chunk_->add_compressed_size(bytes_produced);
      const int sha_retcode = SHA1_Update(&sha1_ctx,
                                           compress_buffer->ptr(),
                                           compress_buffer->used_bytes());
      assert (sha_retcode == 1);
      chunk_->ScheduleWrite(compress_buffer);
    }

    if ((flush == Z_NO_FLUSH && retcode == Z_OK) ||
        (flush == Z_FINISH   && retcode == Z_STREAM_END)) {
      break;
    }

    if (stream.avail_out == 0) {
      compress_buffer = new CharBuffer(4096);
    }
  }

  if (finalize) {
    assert (flush == Z_FINISH);
  }
}

tbb::task* FileScrubbingTask::execute() {
  // Thread Safety:
  //   * Only one executing FileScrubbingTask per File at any time
  //   * Execution is done in-order, thus the File is processed as a stream of
  //     CharBuffers. Each CharBuffer will be processed in one FileScrubbingTask

  if (file_->MightBecomeChunked()) {
    // find chunk cut marks in the current buffer and process all chunks that
    // are fully specified (i.e. not reaching beyond the current buffer)
    const CutMarks cut_marks = FindNextChunkCutMarks();
    CutMarks::const_iterator i    = cut_marks.begin();
    CutMarks::const_iterator iend = cut_marks.end();
    for (; i != iend; ++i) {
      Chunk *fully_defined_chunk = file_->CreateNextChunk(*i);
      assert (fully_defined_chunk->IsFullyDefined());
      QueueForDeferredProcessing(fully_defined_chunk);
    }

    // if we reached the last buffer this input file will produce, all but the
    // last created chunk will be fully defined at this point
    if (IsLastBuffer()) {
      file_->FullyDefineLastChunk();
    }

    // process the current chunk, i.e. the last created chunk that potentially
    // reaches beyond the current buffer or to the end of the file
    Chunk *current_chunk = file_->current_chunk();
    if (current_chunk != NULL) {
      QueueForDeferredProcessing(current_chunk);
    }
  }

  // check if the file has a bulk chunk and continue processing it using the
  // current buffer
  if (file_->HasBulkChunk()) {
    QueueForDeferredProcessing(file_->bulk_chunk());
  }

  // wait for all scheduled chunk processing tasks on the current buffer
  SpawnTasksAndWaitForProcessing();
  reader_->ReleaseBuffer(buffer_);

  // commit the chunks that have been finished during this processing step
  CommitFinishedChunks();

  // go on with the next file buffer
  return Next();
}

void FileScrubbingTask::SpawnTasksAndWaitForProcessing() {
  tbb::task_list tasks;
  std::vector<Chunk*>::const_iterator i    = chunks_to_process_.begin();
  std::vector<Chunk*>::const_iterator iend = chunks_to_process_.end();
  for (; i != iend; ++i) {
    tbb::task *chunk_processing_task =
      new(allocate_child()) ChunkProcessingTask(*i, buffer_);
    tasks.push_back(*chunk_processing_task);
  }

  set_ref_count(chunks_to_process_.size() + 1); // +1 for the wait
  spawn_and_wait_for_all(tasks);
}

void FileScrubbingTask::CommitFinishedChunks() const {
  std::vector<Chunk*>::const_iterator i    = chunks_to_process_.begin();
  std::vector<Chunk*>::const_iterator iend = chunks_to_process_.end();
  for (; i != iend; ++i) {
    Chunk *current_chunk = *i;
    if (current_chunk->IsFullyProcessed()) {
      current_chunk->ScheduleCommit();
    }
  }

}

FileScrubbingTask::CutMarks FileScrubbingTask::FindNextChunkCutMarks() {
  const Chunk *current_chunk = file_->current_chunk();
  assert (file_->MightBecomeChunked());
  assert (current_chunk != NULL);
  assert (current_chunk->size() == 0);
  assert (current_chunk->offset() <= buffer_->base_offset());
  assert (current_chunk->offset() <  buffer_->base_offset() +
                                     static_cast<off_t>(buffer_->used_bytes()));

  CutMarks result;
  off_t next_cut;
  while ((next_cut = file_->FindNextCutMark(buffer_)) != 0) {
    result.push_back(next_cut);
  }

  return result;
}

bool FileScrubbingTask::IsLastBuffer() const {
  return file_->size() == buffer_->base_offset() + buffer_->used_bytes();
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// CLASS HEADER
#include <dali/internal/event/actors/layer-impl.h>

// EXTERNAL INCLUDES

// INTERNAL INCLUDES
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/object/type-registry.h>
#include <dali/internal/event/actors/layer-list.h>
#include <dali/internal/event/common/property-helper.h>
#include <dali/internal/event/common/stage-impl.h>

using Dali::Internal::SceneGraph::UpdateManager;

namespace Dali
{

namespace
{
typedef Dali::Layer::Behavior Behavior;

DALI_ENUM_TO_STRING_TABLE_BEGIN( Behavior )
DALI_ENUM_TO_STRING( Dali::Layer::LAYER_2D )
DALI_ENUM_TO_STRING( Dali::Layer::LAYER_3D )
DALI_ENUM_TO_STRING_TABLE_END( Behavior )
} // namespace

namespace Internal
{

namespace
{

// Properties

//              Name                Type      writable animatable constraint-input  enum for index-checking
DALI_PROPERTY_TABLE_BEGIN
DALI_PROPERTY( "clipping-enable",   BOOLEAN,    true,    false,   true,   Dali::Layer::Property::CLIPPING_ENABLE )
DALI_PROPERTY( "clipping-box",      RECTANGLE,  true,    false,   true,   Dali::Layer::Property::CLIPPING_BOX    )
DALI_PROPERTY( "behavior",          STRING,     true,    false,   false,  Dali::Layer::Property::BEHAVIOR        )
DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )

// Actions

const char* const ACTION_RAISE =           "raise";
const char* const ACTION_LOWER =           "lower";
const char* const ACTION_RAISE_TO_TOP =    "raise-to-top";
const char* const ACTION_LOWER_TO_BOTTOM = "lower-to-bottom";

BaseHandle Create()
{
  return Dali::Layer::New();
}

TypeRegistration mType( typeid( Dali::Layer ), typeid( Dali::Actor ), Create );

TypeAction a1( mType, ACTION_RAISE, &Layer::DoAction );
TypeAction a2( mType, ACTION_LOWER, &Layer::DoAction );
TypeAction a3( mType, ACTION_RAISE_TO_TOP, &Layer::DoAction );
TypeAction a4( mType, ACTION_LOWER_TO_BOTTOM, &Layer::DoAction );

} // unnamed namespace

LayerPtr Layer::New()
{
  LayerPtr layer( new Layer( Actor::LAYER ) );

  // Second-phase construction
  layer->Initialize();

  return layer;
}

LayerPtr Layer::NewRoot( LayerList& layerList, UpdateManager& manager, bool systemLevel )
{
  LayerPtr root( new Layer( Actor::ROOT_LAYER ) );

  // Second-phase construction
  SceneGraph::Layer* layer = static_cast<SceneGraph::Layer*>( root->CreateNode() );
  InstallRootMessage( manager, *layer, systemLevel ); // Transfer ownership to scene-graph

  // Keep a raw pointer to the layer node.
  root->mNode = layer;

  // root actor is immediately considered to be on-stage
  root->mIsOnStage = true;

  // The root actor will not emit a stage connection signal so set the signalled flag here as well
  root->mOnStageSignalled = true;

  // layer-list must be set for the root layer
  root->mLayerList = &layerList;
  layerList.RegisterLayer( *root );

  return root;
}

Layer::Layer( Actor::DerivedType type )
: Actor( type ),
  mLayerList(NULL),
  mClippingBox(0,0,0,0),
  mSortFunction(Layer::ZValue),
  mIsClipping(false),
  mDepthTestDisabled(false),
  mTouchConsumed(false),
  mHoverConsumed(false)
{
}

void Layer::OnInitialize()
{
}

Layer::~Layer()
{
}

unsigned int Layer::GetDepth() const
{
  return mLayerList ? mLayerList->GetDepth( this ) : 0u;
}

void Layer::Raise()
{
  if ( mLayerList )
  {
    mLayerList->RaiseLayer(*this);
  }
}

void Layer::Lower()
{
  if ( mLayerList )
  {
    mLayerList->LowerLayer(*this);
  }
}

void Layer::RaiseAbove( const Internal::Layer& target )
{
  // cannot raise above ourself, both have to be on stage
  if( ( this != &target ) && OnStage() && target.OnStage() )
  {
    // get parameters depth
    const unsigned int targetDepth = target.GetDepth();
    if( GetDepth() < targetDepth )
    {
      MoveAbove( target );
    }
  }
}

void Layer::LowerBelow( const Internal::Layer& target )
{
  // cannot lower below ourself, both have to be on stage
  if( ( this != &target ) && OnStage() && target.OnStage() )
  {
    // get parameters depth
    const unsigned int targetDepth = target.GetDepth();
    if( GetDepth() > targetDepth )
    {
      MoveBelow( target );
    }
  }
}

void Layer::RaiseToTop()
{
  if ( mLayerList )
  {
    mLayerList->RaiseLayerToTop(*this);
  }
}

void Layer::LowerToBottom()
{
  if ( mLayerList )
  {
    mLayerList->LowerLayerToBottom(*this);
  }
}

void Layer::MoveAbove( const Internal::Layer& target )
{
  // cannot raise above ourself, both have to be on stage
  if( ( this != &target ) && mLayerList && target.OnStage() )
  {
    mLayerList->MoveLayerAbove(*this, target );
  }
}

void Layer::MoveBelow( const Internal::Layer& target )
{
  // cannot lower below ourself, both have to be on stage
  if( ( this != &target ) && mLayerList && target.OnStage() )
  {
    mLayerList->MoveLayerBelow(*this, target );
  }
}

void Layer::SetBehavior( Dali::Layer::Behavior behavior )
{
  mBehavior = behavior;

  // notify update side object
  SetBehaviorMessage( GetEventThreadServices(), GetSceneLayerOnStage(), behavior );
}

void Layer::SetClipping(bool enabled)
{
  if (enabled != mIsClipping)
  {
    mIsClipping = enabled;

    // layerNode is being used in a separate thread; queue a message to set the value
    SetClippingMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mIsClipping );
  }
}

void Layer::SetClippingBox(int x, int y, int width, int height)
{
  if( ( x != mClippingBox.x ) ||
      ( y != mClippingBox.y ) ||
      ( width != mClippingBox.width ) ||
      ( height != mClippingBox.height ) )
  {
    // Clipping box is not animatable; this is the most up-to-date value
    mClippingBox.Set(x, y, width, height);

    // Convert mClippingBox to GL based coordinates (from bottom-left)
    ClippingBox clippingBox( mClippingBox );

    StagePtr stage = Stage::GetCurrent();
    if( stage )
    {
      clippingBox.y = stage->GetSize().height - clippingBox.y - clippingBox.height;

      // layerNode is being used in a separate thread; queue a message to set the value
      SetClippingBoxMessage( GetEventThreadServices(), GetSceneLayerOnStage(), clippingBox );
    }
  }
}

void Layer::SetDepthTestDisabled( bool disable )
{
  if( disable != mDepthTestDisabled )
  {
    mDepthTestDisabled = disable;

    // Send message .....
    // layerNode is being used in a separate thread; queue a message to set the value
    SetDepthTestDisabledMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mDepthTestDisabled );
  }
}

bool Layer::IsDepthTestDisabled() const
{
  return mDepthTestDisabled || (mBehavior == Dali::Layer::LAYER_2D);
}

void Layer::SetSortFunction(Dali::Layer::SortFunctionType function)
{
  if( function != mSortFunction )
  {
    mSortFunction = function;

    // layerNode is being used in a separate thread; queue a message to set the value
    SetSortFunctionMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mSortFunction );
  }
}

void Layer::SetTouchConsumed( bool consume )
{
  mTouchConsumed = consume;
}

bool Layer::IsTouchConsumed() const
{
  return mTouchConsumed;
}

void Layer::SetHoverConsumed( bool consume )
{
  mHoverConsumed = consume;
}

bool Layer::IsHoverConsumed() const
{
  return mHoverConsumed;
}

SceneGraph::Node* Layer::CreateNode() const
{
  return SceneGraph::Layer::New();
}

void Layer::OnStageConnectionInternal()
{
  if ( !mIsRoot )
  {
    DALI_ASSERT_DEBUG( NULL == mLayerList );

    // Find the ordered layer-list
    // This is different for Layers added via Integration::GetSystemOverlay()
    for ( Actor* parent = mParent; parent != NULL; parent = parent->GetParent() )
    {
      if( parent->IsLayer() )
      {
        Layer* parentLayer = static_cast< Layer* >( parent ); // cheaper than dynamic_cast
        mLayerList = parentLayer->mLayerList;
      }
    }
  }

  DALI_ASSERT_DEBUG( NULL != mLayerList );
  mLayerList->RegisterLayer( *this );
}

void Layer::OnStageDisconnectionInternal()
{
  mLayerList->UnregisterLayer(*this);

  // mLayerList is only valid when on-stage
  mLayerList = NULL;
}

const SceneGraph::Layer& Layer::GetSceneLayerOnStage() const
{
  DALI_ASSERT_DEBUG( mNode != NULL );
  return dynamic_cast< const SceneGraph::Layer& >( *mNode );
}

unsigned int Layer::GetDefaultPropertyCount() const
{
  return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
}

void Layer::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
{
  Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
  indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );

  int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
  {
    indices.PushBack( index );
  }
}

bool Layer::IsDefaultPropertyWritable( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyWritable( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].writable;
}

bool Layer::IsDefaultPropertyAnimatable( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyAnimatable( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].animatable;
}

bool Layer::IsDefaultPropertyAConstraintInput( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyAConstraintInput( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].constraintInput;
}

Property::Type Layer::GetDefaultPropertyType( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::GetDefaultPropertyType( index );
  }

  index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;

  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
  {
    return DEFAULT_PROPERTY_DETAILS[index].type;
  }

  // index out-of-bounds
  return Property::NONE;
}

const char* Layer::GetDefaultPropertyName( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::GetDefaultPropertyName( index );
  }

  index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
  {
    return DEFAULT_PROPERTY_DETAILS[index].name;
  }

  return NULL;
}

Property::Index Layer::GetDefaultPropertyIndex(const std::string& name) const
{
  Property::Index index = Property::INVALID_INDEX;

  // Look for name in current class' default properties
  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
  {
    const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[i];
    if( 0 == name.compare( property->name ) ) // dont want to convert rhs to string
    {
      index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
      break;
    }
  }
  if( Property::INVALID_INDEX == index )
  {
    // If not found, check in base class
    index = Actor::GetDefaultPropertyIndex( name );
  }

  return index;
}

void Layer::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    Actor::SetDefaultProperty( index, propertyValue );
  }
  else
  {
    switch( index )
    {
      case Dali::Layer::Property::CLIPPING_ENABLE:
      {
        SetClipping( propertyValue.Get<bool>() );
        break;
      }
      case Dali::Layer::Property::CLIPPING_BOX:
      {
        Rect<int> clippingBox( propertyValue.Get<Rect<int> >() );
        SetClippingBox( clippingBox.x, clippingBox.y, clippingBox.width, clippingBox.height );
        break;
      }
      case Dali::Layer::Property::BEHAVIOR:
      {
        Behavior behavior(Dali::Layer::LAYER_2D);
        if( Scripting::GetEnumeration< Behavior >( propertyValue.Get< std::string >().c_str(), BehaviorTable, BehaviorTableCount, behavior ) )
        {
          SetBehavior( behavior );
        }
        break;
      }
      default:
      {
        DALI_LOG_WARNING( "Unknown property (%d)\n", index );
        break;
      }
    } // switch(index)

  } // else
}

Property::Value Layer::GetDefaultProperty( Property::Index index ) const
{
  Property::Value ret;
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    ret = Actor::GetDefaultProperty( index );
  }
  else
  {
    switch( index )
    {
      case Dali::Layer::Property::CLIPPING_ENABLE:
      {
        ret = mIsClipping;
        break;
      }
      case Dali::Layer::Property::CLIPPING_BOX:
      {
        ret = mClippingBox;
        break;
      }
      case Dali::Layer::Property::BEHAVIOR:
      {
        ret = Scripting::GetLinearEnumerationName< Behavior >( GetBehavior(), BehaviorTable, BehaviorTableCount );
        break;
      }
      default:
      {
        DALI_LOG_WARNING( "Unknown property (%d)\n", index );
        break;
      }
    } // switch(index)
  }

  return ret;
}

bool Layer::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& /*attributes*/ )
{
  bool done = false;
  Layer* layer = dynamic_cast<Layer*>( object );

  if( layer )
  {
    if( 0 == actionName.compare( ACTION_RAISE ) )
    {
      layer->Raise();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_LOWER ) )
    {
      layer->Lower();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_RAISE_TO_TOP ) )
    {
      layer->RaiseToTop();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_LOWER_TO_BOTTOM ) )
    {
      layer->LowerToBottom();
      done = true;
    }
  }

  return done;
}

} // namespace Internal

} // namespace Dali
<commit_msg>Set default behavior in Layer - to fix target UTC fail<commit_after>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// CLASS HEADER
#include <dali/internal/event/actors/layer-impl.h>

// EXTERNAL INCLUDES

// INTERNAL INCLUDES
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/object/type-registry.h>
#include <dali/internal/event/actors/layer-list.h>
#include <dali/internal/event/common/property-helper.h>
#include <dali/internal/event/common/stage-impl.h>

using Dali::Internal::SceneGraph::UpdateManager;

namespace Dali
{

namespace
{
typedef Dali::Layer::Behavior Behavior;

DALI_ENUM_TO_STRING_TABLE_BEGIN( Behavior )
DALI_ENUM_TO_STRING( Dali::Layer::LAYER_2D )
DALI_ENUM_TO_STRING( Dali::Layer::LAYER_3D )
DALI_ENUM_TO_STRING_TABLE_END( Behavior )
} // namespace

namespace Internal
{

namespace
{

// Properties

//              Name                Type      writable animatable constraint-input  enum for index-checking
DALI_PROPERTY_TABLE_BEGIN
DALI_PROPERTY( "clipping-enable",   BOOLEAN,    true,    false,   true,   Dali::Layer::Property::CLIPPING_ENABLE )
DALI_PROPERTY( "clipping-box",      RECTANGLE,  true,    false,   true,   Dali::Layer::Property::CLIPPING_BOX    )
DALI_PROPERTY( "behavior",          STRING,     true,    false,   false,  Dali::Layer::Property::BEHAVIOR        )
DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )

// Actions

const char* const ACTION_RAISE =           "raise";
const char* const ACTION_LOWER =           "lower";
const char* const ACTION_RAISE_TO_TOP =    "raise-to-top";
const char* const ACTION_LOWER_TO_BOTTOM = "lower-to-bottom";

BaseHandle Create()
{
  return Dali::Layer::New();
}

TypeRegistration mType( typeid( Dali::Layer ), typeid( Dali::Actor ), Create );

TypeAction a1( mType, ACTION_RAISE, &Layer::DoAction );
TypeAction a2( mType, ACTION_LOWER, &Layer::DoAction );
TypeAction a3( mType, ACTION_RAISE_TO_TOP, &Layer::DoAction );
TypeAction a4( mType, ACTION_LOWER_TO_BOTTOM, &Layer::DoAction );

} // unnamed namespace

LayerPtr Layer::New()
{
  LayerPtr layer( new Layer( Actor::LAYER ) );

  // Second-phase construction
  layer->Initialize();

  return layer;
}

LayerPtr Layer::NewRoot( LayerList& layerList, UpdateManager& manager, bool systemLevel )
{
  LayerPtr root( new Layer( Actor::ROOT_LAYER ) );

  // Second-phase construction
  SceneGraph::Layer* layer = static_cast<SceneGraph::Layer*>( root->CreateNode() );
  InstallRootMessage( manager, *layer, systemLevel ); // Transfer ownership to scene-graph

  // Keep a raw pointer to the layer node.
  root->mNode = layer;

  // root actor is immediately considered to be on-stage
  root->mIsOnStage = true;

  // The root actor will not emit a stage connection signal so set the signalled flag here as well
  root->mOnStageSignalled = true;

  // layer-list must be set for the root layer
  root->mLayerList = &layerList;
  layerList.RegisterLayer( *root );

  return root;
}

Layer::Layer( Actor::DerivedType type )
: Actor( type ),
  mLayerList(NULL),
  mClippingBox(0,0,0,0),
  mSortFunction(Layer::ZValue),
  mBehavior(Dali::Layer::LAYER_2D),
  mIsClipping(false),
  mDepthTestDisabled(false),
  mTouchConsumed(false),
  mHoverConsumed(false)
{
}

void Layer::OnInitialize()
{
}

Layer::~Layer()
{
}

unsigned int Layer::GetDepth() const
{
  return mLayerList ? mLayerList->GetDepth( this ) : 0u;
}

void Layer::Raise()
{
  if ( mLayerList )
  {
    mLayerList->RaiseLayer(*this);
  }
}

void Layer::Lower()
{
  if ( mLayerList )
  {
    mLayerList->LowerLayer(*this);
  }
}

void Layer::RaiseAbove( const Internal::Layer& target )
{
  // cannot raise above ourself, both have to be on stage
  if( ( this != &target ) && OnStage() && target.OnStage() )
  {
    // get parameters depth
    const unsigned int targetDepth = target.GetDepth();
    if( GetDepth() < targetDepth )
    {
      MoveAbove( target );
    }
  }
}

void Layer::LowerBelow( const Internal::Layer& target )
{
  // cannot lower below ourself, both have to be on stage
  if( ( this != &target ) && OnStage() && target.OnStage() )
  {
    // get parameters depth
    const unsigned int targetDepth = target.GetDepth();
    if( GetDepth() > targetDepth )
    {
      MoveBelow( target );
    }
  }
}

void Layer::RaiseToTop()
{
  if ( mLayerList )
  {
    mLayerList->RaiseLayerToTop(*this);
  }
}

void Layer::LowerToBottom()
{
  if ( mLayerList )
  {
    mLayerList->LowerLayerToBottom(*this);
  }
}

void Layer::MoveAbove( const Internal::Layer& target )
{
  // cannot raise above ourself, both have to be on stage
  if( ( this != &target ) && mLayerList && target.OnStage() )
  {
    mLayerList->MoveLayerAbove(*this, target );
  }
}

void Layer::MoveBelow( const Internal::Layer& target )
{
  // cannot lower below ourself, both have to be on stage
  if( ( this != &target ) && mLayerList && target.OnStage() )
  {
    mLayerList->MoveLayerBelow(*this, target );
  }
}

void Layer::SetBehavior( Dali::Layer::Behavior behavior )
{
  mBehavior = behavior;

  // notify update side object
  SetBehaviorMessage( GetEventThreadServices(), GetSceneLayerOnStage(), behavior );
}

void Layer::SetClipping(bool enabled)
{
  if (enabled != mIsClipping)
  {
    mIsClipping = enabled;

    // layerNode is being used in a separate thread; queue a message to set the value
    SetClippingMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mIsClipping );
  }
}

void Layer::SetClippingBox(int x, int y, int width, int height)
{
  if( ( x != mClippingBox.x ) ||
      ( y != mClippingBox.y ) ||
      ( width != mClippingBox.width ) ||
      ( height != mClippingBox.height ) )
  {
    // Clipping box is not animatable; this is the most up-to-date value
    mClippingBox.Set(x, y, width, height);

    // Convert mClippingBox to GL based coordinates (from bottom-left)
    ClippingBox clippingBox( mClippingBox );

    StagePtr stage = Stage::GetCurrent();
    if( stage )
    {
      clippingBox.y = stage->GetSize().height - clippingBox.y - clippingBox.height;

      // layerNode is being used in a separate thread; queue a message to set the value
      SetClippingBoxMessage( GetEventThreadServices(), GetSceneLayerOnStage(), clippingBox );
    }
  }
}

void Layer::SetDepthTestDisabled( bool disable )
{
  if( disable != mDepthTestDisabled )
  {
    mDepthTestDisabled = disable;

    // Send message .....
    // layerNode is being used in a separate thread; queue a message to set the value
    SetDepthTestDisabledMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mDepthTestDisabled );
  }
}

bool Layer::IsDepthTestDisabled() const
{
  return mDepthTestDisabled || (mBehavior == Dali::Layer::LAYER_2D);
}

void Layer::SetSortFunction(Dali::Layer::SortFunctionType function)
{
  if( function != mSortFunction )
  {
    mSortFunction = function;

    // layerNode is being used in a separate thread; queue a message to set the value
    SetSortFunctionMessage( GetEventThreadServices(), GetSceneLayerOnStage(), mSortFunction );
  }
}

void Layer::SetTouchConsumed( bool consume )
{
  mTouchConsumed = consume;
}

bool Layer::IsTouchConsumed() const
{
  return mTouchConsumed;
}

void Layer::SetHoverConsumed( bool consume )
{
  mHoverConsumed = consume;
}

bool Layer::IsHoverConsumed() const
{
  return mHoverConsumed;
}

SceneGraph::Node* Layer::CreateNode() const
{
  return SceneGraph::Layer::New();
}

void Layer::OnStageConnectionInternal()
{
  if ( !mIsRoot )
  {
    DALI_ASSERT_DEBUG( NULL == mLayerList );

    // Find the ordered layer-list
    // This is different for Layers added via Integration::GetSystemOverlay()
    for ( Actor* parent = mParent; parent != NULL; parent = parent->GetParent() )
    {
      if( parent->IsLayer() )
      {
        Layer* parentLayer = static_cast< Layer* >( parent ); // cheaper than dynamic_cast
        mLayerList = parentLayer->mLayerList;
      }
    }
  }

  DALI_ASSERT_DEBUG( NULL != mLayerList );
  mLayerList->RegisterLayer( *this );
}

void Layer::OnStageDisconnectionInternal()
{
  mLayerList->UnregisterLayer(*this);

  // mLayerList is only valid when on-stage
  mLayerList = NULL;
}

const SceneGraph::Layer& Layer::GetSceneLayerOnStage() const
{
  DALI_ASSERT_DEBUG( mNode != NULL );
  return dynamic_cast< const SceneGraph::Layer& >( *mNode );
}

unsigned int Layer::GetDefaultPropertyCount() const
{
  return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
}

void Layer::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
{
  Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
  indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );

  int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
  {
    indices.PushBack( index );
  }
}

bool Layer::IsDefaultPropertyWritable( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyWritable( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].writable;
}

bool Layer::IsDefaultPropertyAnimatable( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyAnimatable( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].animatable;
}

bool Layer::IsDefaultPropertyAConstraintInput( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::IsDefaultPropertyAConstraintInput( index );
  }

  return DEFAULT_PROPERTY_DETAILS[ index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX ].constraintInput;
}

Property::Type Layer::GetDefaultPropertyType( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::GetDefaultPropertyType( index );
  }

  index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;

  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
  {
    return DEFAULT_PROPERTY_DETAILS[index].type;
  }

  // index out-of-bounds
  return Property::NONE;
}

const char* Layer::GetDefaultPropertyName( Property::Index index ) const
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    return Actor::GetDefaultPropertyName( index );
  }

  index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
  {
    return DEFAULT_PROPERTY_DETAILS[index].name;
  }

  return NULL;
}

Property::Index Layer::GetDefaultPropertyIndex(const std::string& name) const
{
  Property::Index index = Property::INVALID_INDEX;

  // Look for name in current class' default properties
  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
  {
    const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[i];
    if( 0 == name.compare( property->name ) ) // dont want to convert rhs to string
    {
      index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
      break;
    }
  }
  if( Property::INVALID_INDEX == index )
  {
    // If not found, check in base class
    index = Actor::GetDefaultPropertyIndex( name );
  }

  return index;
}

void Layer::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
{
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    Actor::SetDefaultProperty( index, propertyValue );
  }
  else
  {
    switch( index )
    {
      case Dali::Layer::Property::CLIPPING_ENABLE:
      {
        SetClipping( propertyValue.Get<bool>() );
        break;
      }
      case Dali::Layer::Property::CLIPPING_BOX:
      {
        Rect<int> clippingBox( propertyValue.Get<Rect<int> >() );
        SetClippingBox( clippingBox.x, clippingBox.y, clippingBox.width, clippingBox.height );
        break;
      }
      case Dali::Layer::Property::BEHAVIOR:
      {
        Behavior behavior(Dali::Layer::LAYER_2D);
        if( Scripting::GetEnumeration< Behavior >( propertyValue.Get< std::string >().c_str(), BehaviorTable, BehaviorTableCount, behavior ) )
        {
          SetBehavior( behavior );
        }
        break;
      }
      default:
      {
        DALI_LOG_WARNING( "Unknown property (%d)\n", index );
        break;
      }
    } // switch(index)

  } // else
}

Property::Value Layer::GetDefaultProperty( Property::Index index ) const
{
  Property::Value ret;
  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
  {
    ret = Actor::GetDefaultProperty( index );
  }
  else
  {
    switch( index )
    {
      case Dali::Layer::Property::CLIPPING_ENABLE:
      {
        ret = mIsClipping;
        break;
      }
      case Dali::Layer::Property::CLIPPING_BOX:
      {
        ret = mClippingBox;
        break;
      }
      case Dali::Layer::Property::BEHAVIOR:
      {
        ret = Scripting::GetLinearEnumerationName< Behavior >( GetBehavior(), BehaviorTable, BehaviorTableCount );
        break;
      }
      default:
      {
        DALI_LOG_WARNING( "Unknown property (%d)\n", index );
        break;
      }
    } // switch(index)
  }

  return ret;
}

bool Layer::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& /*attributes*/ )
{
  bool done = false;
  Layer* layer = dynamic_cast<Layer*>( object );

  if( layer )
  {
    if( 0 == actionName.compare( ACTION_RAISE ) )
    {
      layer->Raise();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_LOWER ) )
    {
      layer->Lower();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_RAISE_TO_TOP ) )
    {
      layer->RaiseToTop();
      done = true;
    }
    else if( 0 == actionName.compare( ACTION_LOWER_TO_BOTTOM ) )
    {
      layer->LowerToBottom();
      done = true;
    }
  }

  return done;
}

} // namespace Internal

} // namespace Dali
<|endoftext|>