<commit_before>#pragma once

#include <pip/syntax.hpp>
#include <functional>
#include <unordered_set>

namespace pip
{
  // Kinds of declarations.
  enum decl_kind : int
  {
    dk_program,
    dk_table,
    dk_meter,
  };

  // Kinds of matching strategies.
  enum rule_kind : int
  {
    rk_exact,
    rk_prefix,
    rk_wildcard,
    rk_range,
    rk_expr,
  };

  /// The base class of all declarations. A declaration introduces a named
  /// entity.
  struct decl : cc::node
  {
    decl(decl_kind k, symbol* id)
      : cc::node(k, {}), id(id)
    { }

    void dump();

    symbol* id;

    virtual ~decl() {}
  };

  /// A dataplane program. A dataplane program is defined (primarily) by a
  /// list of match table and their associated actions.
  ///
  /// \todo How do we (or should we?) incorporate other kinds of declarations.
  /// For example, should we declare ports? Should we declare meters? Group
  /// actions? Do we need to process the list of declarations to find e.g.,
  /// the entry table?
  struct program_decl : decl
  {
    program_decl(const decl_seq& ds)
      : decl(dk_program, nullptr), decls(ds)
    { }

    program_decl(decl_seq&& ds)
      : decl(dk_program, nullptr), decls(std::move(ds))
    { }

    /// A list of declarations.
    decl_seq decls;
  };

  /// Represents a match in a table. This is a key/value pair where the key
  /// is a literal expression, and the value is an action list expression.
  /// The rule kind of this object must match that of the table it
  /// appears in.
  struct rule : cc::node
  {
    rule(rule_kind k, expr* key, const action_seq& val)
      : cc::node(0, {}), kind(k), key(key), acts(val)
    { }

    rule(rule_kind k, expr* key, action_seq&& val)
      : cc::node(0, {}), kind(k), key(key), acts(std::move(val))
    { }

    /// The kind of matching operation.
    rule_kind kind;

    /// The matched key -- a literal.
    expr* key;

    /// The list of actions to be executed.
    action_seq acts;
  };

  /// A lookup table. Match tables are determined by a matching kind, which
  /// prescribes the how keys are found in the table.
  ///
  /// \todo Support general purpose tables, that can include arbitrary forms
  /// of matching (e.g., wildcard and exact). Note an exact match in a wildcard
  /// table is simply one with no don't-care bits. Maybe we don't need to
  /// generalize this so much.
  struct table_decl : decl
  {
    table_decl(symbol* id, rule_kind k, const action_seq& as, const rule_seq& ms)
      : decl(dk_table, id), rule(k), prep(as), rules(ms)
    { }

    table_decl(symbol* id, rule_kind k, action_seq&& as, rule_seq&& ms)
      : decl(dk_table, id), rule(k), prep(std::move(as)), rules(std::move(ms))
    { }

    /// The kind of table.
    rule_kind rule;

    /// The sequence of actions used to form the key for lookup.
    action_seq prep;

    /// The content of the action table.
    rule_seq rules;

    /// A hash table to match keys for exact-match tables
    std::unordered_set<std::uint64_t, std::hash<std::uint64_t>> key_table;
  };

  /// A flow metering device.
  ///
  /// \todo Implement this?
  struct meter_decl : decl
  {
    meter_decl(symbol* id)
      : decl(dk_meter, id)
    { }
  };

// -------------------------------------------------------------------------- //
// Operations

  /// Returns the kind of a declaration.
  inline decl_kind
  get_kind(const decl* d)
  {
    return static_cast<decl_kind>(d->kind);
  }

} // namespace pip

// -------------------------------------------------------------------------- //
// Casting

namespace cc
{
  template<>
  struct node_info<pip::program_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_program; }
  };

  template<>
  struct node_info<pip::table_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_table; }
  };

  template<>
  struct node_info<pip::meter_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_meter; }
  };

} // namespace cc
<commit_msg>Memory management for declarations.<commit_after>#pragma once

#include <pip/syntax.hpp>
#include <functional>
#include <unordered_set>

namespace pip
{
  // Kinds of declarations.
  enum decl_kind : int
  {
    dk_program,
    dk_table,
    dk_meter,
  };

  // Kinds of matching strategies.
  enum rule_kind : int
  {
    rk_exact,
    rk_prefix,
    rk_wildcard,
    rk_range,
    rk_expr,
  };

  /// The base class of all declarations. A declaration introduces a named
  /// entity.
  struct decl : cc::node
  {
    decl(decl_kind k, symbol* id)
      : cc::node(k, {}), id(id)
    { }

    void dump();

    symbol* id;

    virtual ~decl() {}
  };

  /// A dataplane program. A dataplane program is defined (primarily) by a
  /// list of match table and their associated actions.
  ///
  /// \todo How do we (or should we?) incorporate other kinds of declarations.
  /// For example, should we declare ports? Should we declare meters? Group
  /// actions? Do we need to process the list of declarations to find e.g.,
  /// the entry table?
  struct program_decl : decl
  {
    program_decl(const decl_seq& ds)
      : decl(dk_program, nullptr), decls(ds)
    { }

    program_decl(decl_seq&& ds)
      : decl(dk_program, nullptr), decls(std::move(ds))
    { }

    ~program_decl()
    { for(auto d : decls) delete d; }

    /// A list of declarations.
    decl_seq decls;
  };

  /// Represents a match in a table. This is a key/value pair where the key
  /// is a literal expression, and the value is an action list expression.
  /// The rule kind of this object must match that of the table it
  /// appears in.
  struct rule : cc::node
  {
    rule(rule_kind k, expr* key, const action_seq& val)
      : cc::node(0, {}), kind(k), key(key), acts(val)
    { }

    rule(rule_kind k, expr* key, action_seq&& val)
      : cc::node(0, {}), kind(k), key(key), acts(std::move(val))
    { }

    /// The kind of matching operation.
    rule_kind kind;

    /// The matched key -- a literal.
    expr* key;

    /// The list of actions to be executed.
    action_seq acts;
  };

  /// A lookup table. Match tables are determined by a matching kind, which
  /// prescribes the how keys are found in the table.
  ///
  /// \todo Support general purpose tables, that can include arbitrary forms
  /// of matching (e.g., wildcard and exact). Note an exact match in a wildcard
  /// table is simply one with no don't-care bits. Maybe we don't need to
  /// generalize this so much.
  struct table_decl : decl
  {
    table_decl(symbol* id, rule_kind k, const action_seq& as, const rule_seq& ms)
      : decl(dk_table, id), rule(k), prep(as), rules(ms)
    { }

    table_decl(symbol* id, rule_kind k, action_seq&& as, rule_seq&& ms)
      : decl(dk_table, id), rule(k), prep(std::move(as)), rules(std::move(ms))
    { }

    ~table_decl()
    { for(auto r : rules) delete r; }

    /// The kind of table.
    rule_kind rule;

    /// The sequence of actions used to form the key for lookup.
    action_seq prep;

    /// The content of the action table.
    rule_seq rules;

    /// A hash table to match keys for exact-match tables
    std::unordered_set<std::uint64_t, std::hash<std::uint64_t>> key_table;
  };

  /// A flow metering device.
  ///
  /// \todo Implement this?
  struct meter_decl : decl
  {
    meter_decl(symbol* id)
      : decl(dk_meter, id)
    { }
  };

// -------------------------------------------------------------------------- //
// Operations

  /// Returns the kind of a declaration.
  inline decl_kind
  get_kind(const decl* d)
  {
    return static_cast<decl_kind>(d->kind);
  }

} // namespace pip

// -------------------------------------------------------------------------- //
// Casting

namespace cc
{
  template<>
  struct node_info<pip::program_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_program; }
  };

  template<>
  struct node_info<pip::table_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_table; }
  };

  template<>
  struct node_info<pip::meter_decl>
  {
    static bool
    has_kind(const node* n) { return get_node_kind(n) == pip::dk_meter; }
  };

} // namespace cc
<|endoftext|>


<commit_before>// Copyright (c) 2012-2013 The Bitcoin Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "util/system.h"

#include "support/allocators/zeroafterfree.h"
#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(arena_tests)
{
    // Fake memory base address for testing
    // without actually using memory.
    void *synth_base = reinterpret_cast<void*>(0x08000000);
    const size_t synth_size = 1024*1024;
    Arena b(synth_base, synth_size, 16);
    void *chunk = b.alloc(1000);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(chunk != nullptr);
    BOOST_CHECK(b.stats().used == 1008); // Aligned to 16
    BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?
    b.free(chunk);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 0);
    BOOST_CHECK(b.stats().free == synth_size);
    try { // Test exception on double-free
        b.free(chunk);
        BOOST_CHECK(0);
    } catch(std::runtime_error &)
    {
    }

    void *a0 = b.alloc(128);
    BOOST_CHECK(a0 == synth_base); // first allocation must start at beginning
    void *a1 = b.alloc(256);
    void *a2 = b.alloc(512);
    BOOST_CHECK(b.stats().used == 896);
    BOOST_CHECK(b.stats().total == synth_size);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    b.free(a0);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 768);
    b.free(a1);
    BOOST_CHECK(b.stats().used == 512);
    void *a3 = b.alloc(128);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 640);
    b.free(a2);
    BOOST_CHECK(b.stats().used == 128);
    b.free(a3);
    BOOST_CHECK(b.stats().used == 0);
    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);

    std::vector<void*> addr;
    BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr
#ifdef ARENA_DEBUG
    b.walk();
#endif
    // Sweeping allocate all memory
    for (int x=0; x<1024; ++x)
        addr.push_back(b.alloc(1024));
    BOOST_CHECK(addr[0] == synth_base); // first allocation must start at beginning
    BOOST_CHECK(b.stats().free == 0);
    BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr
    BOOST_CHECK(b.alloc(0) == nullptr);
    for (int x=0; x<1024; ++x)
        b.free(addr[x]);
    addr.clear();
    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);

    // Now in the other direction...
    for (int x=0; x<1024; ++x)
        addr.push_back(b.alloc(1024));
    for (int x=0; x<1024; ++x)
        b.free(addr[1023-x]);
    addr.clear();

    // Now allocate in smaller unequal chunks, then deallocate haphazardly
    // Not all the chunks will succeed allocating, but freeing nullptr is
    // allowed so that is no problem.
    for (int x=0; x<2048; ++x)
        addr.push_back(b.alloc(x+1));
    for (int x=0; x<2048; ++x)
        b.free(addr[((x*23)%2048)^242]);
    addr.clear();

    // Go entirely wild: free and alloc interleaved,
    // generate targets and sizes using pseudo-randomness.
    for (int x=0; x<2048; ++x)
        addr.push_back(0);
    uint32_t s = 0x12345678;
    for (int x=0; x<5000; ++x) {
        int idx = s & (addr.size()-1);
        if (s & 0x80000000) {
            b.free(addr[idx]);
            addr[idx] = 0;
        } else if(!addr[idx]) {
            addr[idx] = b.alloc((s >> 16) & 2047);
        }
        bool lsb = s & 1;
        s >>= 1;
        if (lsb)
            s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
    }
    for (void *ptr: addr)
        b.free(ptr);
    addr.clear();

    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);
}

/** Mock LockedPageAllocator for testing */
class TestLockedPageAllocator: public LockedPageAllocator
{
public:
    TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}
    void* AllocateLocked(size_t len, bool *lockingSuccess)
    {
        *lockingSuccess = false;
        if (count > 0) {
            --count;

            if (lockedcount > 0) {
                --lockedcount;
                *lockingSuccess = true;
            }

            return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory
        }
        return 0;
    }
    void FreeLocked(void* addr, size_t len)
    {
    }
    size_t GetLimit()
    {
        return std::numeric_limits<size_t>::max();
    }
private:
    int count;
    int lockedcount;
};

BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
{
    // Test over three virtual arenas, of which one will succeed being locked
    std::unique_ptr<LockedPageAllocator> x(new TestLockedPageAllocator(3, 1));
    LockedPool pool(std::move(x));
    BOOST_CHECK(pool.stats().total == 0);
    BOOST_CHECK(pool.stats().locked == 0);

    void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a0);
    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
    void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a1);
    void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a2);
    void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a3);
    void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a4);
    void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a5);
    // We've passed a count of three arenas, so this allocation should fail
    void *a6 = pool.alloc(16);
    BOOST_CHECK(!a6);

    pool.free(a0);
    pool.free(a2);
    pool.free(a4);
    pool.free(a1);
    pool.free(a3);
    pool.free(a5);
    BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);
    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
    BOOST_CHECK(pool.stats().used == 0);
}

// These tests used the live LockedPoolManager object, this is also used
// by other tests so the conditions are somewhat less controllable and thus the
// tests are somewhat more error-prone.
BOOST_AUTO_TEST_CASE(lockedpool_tests_live)
{
    LockedPoolManager &pool = LockedPoolManager::Instance();
    LockedPool::Stats initial = pool.stats();

    void *a0 = pool.alloc(16);
    BOOST_CHECK(a0);
    // Test reading and writing the allocated memory
    *((uint32_t*)a0) = 0x1234;
    BOOST_CHECK(*((uint32_t*)a0) == 0x1234);

    pool.free(a0);
    try { // Test exception on double-free
        pool.free(a0);
        BOOST_CHECK(0);
    } catch(std::runtime_error &)
    {
    }
    // If more than one new arena was allocated for the above tests, something is wrong
    BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));
    // Usage must be back to where it started
    BOOST_CHECK(pool.stats().used == initial.used);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>LockedPool: test handling of invalid allocations<commit_after>// Copyright (c) 2012-2013 The Bitcoin Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "util/system.h"

#include "support/allocators/zeroafterfree.h"
#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(arena_tests)
{
    // Fake memory base address for testing
    // without actually using memory.
    void *synth_base = reinterpret_cast<void*>(0x08000000);
    const size_t synth_size = 1024*1024;
    Arena b(synth_base, synth_size, 16);
    void *chunk = b.alloc(1000);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(chunk != nullptr);
    BOOST_CHECK(b.stats().used == 1008); // Aligned to 16
    BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?
    b.free(chunk);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 0);
    BOOST_CHECK(b.stats().free == synth_size);
    try { // Test exception on double-free
        b.free(chunk);
        BOOST_CHECK(0);
    } catch(std::runtime_error &)
    {
    }

    void *a0 = b.alloc(128);
    BOOST_CHECK(a0 == synth_base); // first allocation must start at beginning
    void *a1 = b.alloc(256);
    void *a2 = b.alloc(512);
    BOOST_CHECK(b.stats().used == 896);
    BOOST_CHECK(b.stats().total == synth_size);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    b.free(a0);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 768);
    b.free(a1);
    BOOST_CHECK(b.stats().used == 512);
    void *a3 = b.alloc(128);
#ifdef ARENA_DEBUG
    b.walk();
#endif
    BOOST_CHECK(b.stats().used == 640);
    b.free(a2);
    BOOST_CHECK(b.stats().used == 128);
    b.free(a3);
    BOOST_CHECK(b.stats().used == 0);
    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);

    std::vector<void*> addr;
    BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr
#ifdef ARENA_DEBUG
    b.walk();
#endif
    // Sweeping allocate all memory
    for (int x=0; x<1024; ++x)
        addr.push_back(b.alloc(1024));
    BOOST_CHECK(addr[0] == synth_base); // first allocation must start at beginning
    BOOST_CHECK(b.stats().free == 0);
    BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr
    BOOST_CHECK(b.alloc(0) == nullptr);
    for (int x=0; x<1024; ++x)
        b.free(addr[x]);
    addr.clear();
    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);

    // Now in the other direction...
    for (int x=0; x<1024; ++x)
        addr.push_back(b.alloc(1024));
    for (int x=0; x<1024; ++x)
        b.free(addr[1023-x]);
    addr.clear();

    // Now allocate in smaller unequal chunks, then deallocate haphazardly
    // Not all the chunks will succeed allocating, but freeing nullptr is
    // allowed so that is no problem.
    for (int x=0; x<2048; ++x)
        addr.push_back(b.alloc(x+1));
    for (int x=0; x<2048; ++x)
        b.free(addr[((x*23)%2048)^242]);
    addr.clear();

    // Go entirely wild: free and alloc interleaved,
    // generate targets and sizes using pseudo-randomness.
    for (int x=0; x<2048; ++x)
        addr.push_back(0);
    uint32_t s = 0x12345678;
    for (int x=0; x<5000; ++x) {
        int idx = s & (addr.size()-1);
        if (s & 0x80000000) {
            b.free(addr[idx]);
            addr[idx] = 0;
        } else if(!addr[idx]) {
            addr[idx] = b.alloc((s >> 16) & 2047);
        }
        bool lsb = s & 1;
        s >>= 1;
        if (lsb)
            s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
    }
    for (void *ptr: addr)
        b.free(ptr);
    addr.clear();

    BOOST_CHECK(b.stats().total == synth_size);
    BOOST_CHECK(b.stats().free == synth_size);
}

/** Mock LockedPageAllocator for testing */
class TestLockedPageAllocator: public LockedPageAllocator
{
public:
    TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}
    void* AllocateLocked(size_t len, bool *lockingSuccess)
    {
        *lockingSuccess = false;
        if (count > 0) {
            --count;

            if (lockedcount > 0) {
                --lockedcount;
                *lockingSuccess = true;
            }

            return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory
        }
        return 0;
    }
    void FreeLocked(void* addr, size_t len)
    {
    }
    size_t GetLimit()
    {
        return std::numeric_limits<size_t>::max();
    }
private:
    int count;
    int lockedcount;
};

BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
{
    // Test over three virtual arenas, of which one will succeed being locked
    std::unique_ptr<LockedPageAllocator> x(new TestLockedPageAllocator(3, 1));
    LockedPool pool(std::move(x));
    BOOST_CHECK(pool.stats().total == 0);
    BOOST_CHECK(pool.stats().locked == 0);

    // Ensure unreasonable requests are refused without allocating anything
    void *invalid_toosmall = pool.alloc(0);
    BOOST_CHECK(invalid_toosmall == nullptr);
    BOOST_CHECK(pool.stats().used == 0);
    BOOST_CHECK(pool.stats().free == 0);
    void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);
    BOOST_CHECK(invalid_toobig == nullptr);
    BOOST_CHECK(pool.stats().used == 0);
    BOOST_CHECK(pool.stats().free == 0);

    void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a0);
    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
    void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a1);
    void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a2);
    void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a3);
    void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a4);
    void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);
    BOOST_CHECK(a5);
    // We've passed a count of three arenas, so this allocation should fail
    void *a6 = pool.alloc(16);
    BOOST_CHECK(!a6);

    pool.free(a0);
    pool.free(a2);
    pool.free(a4);
    pool.free(a1);
    pool.free(a3);
    pool.free(a5);
    BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);
    BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
    BOOST_CHECK(pool.stats().used == 0);
}

// These tests used the live LockedPoolManager object, this is also used
// by other tests so the conditions are somewhat less controllable and thus the
// tests are somewhat more error-prone.
BOOST_AUTO_TEST_CASE(lockedpool_tests_live)
{
    LockedPoolManager &pool = LockedPoolManager::Instance();
    LockedPool::Stats initial = pool.stats();

    void *a0 = pool.alloc(16);
    BOOST_CHECK(a0);
    // Test reading and writing the allocated memory
    *((uint32_t*)a0) = 0x1234;
    BOOST_CHECK(*((uint32_t*)a0) == 0x1234);

    pool.free(a0);
    try { // Test exception on double-free
        pool.free(a0);
        BOOST_CHECK(0);
    } catch(std::runtime_error &)
    {
    }
    // If more than one new arena was allocated for the above tests, something is wrong
    BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));
    // Usage must be back to where it started
    BOOST_CHECK(pool.stats().used == initial.used);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>10966be6-2748-11e6-8f38-e0f84713e7b8<commit_msg>ashley broke it<commit_after>10a6c2ca-2748-11e6-9c7b-e0f84713e7b8<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "Lex.h"
#include "CmdInputFactor.h"
#include "GrammarAnalyzer.h"
#include "JZLogger.h"

//basic function declaration
TEST(GrammarAnalyzer, FunctionBasic0)
{
  int argc = 2;
  char argv0[128] = {0},argv1[128] = {0};
  strcpy(argv0,"tester");
  strcpy(argv1,"./test/GrammarSample/function_sample_0");
  char* argv[2] = {argv0,argv1};

	//analyze command line input
	CmdInputFactor::getInstance()->analyze(argc, argv);

	//now begin to analyze the files input from command line
	string toCompileFile = CmdInputFactor::getInstance()->getNextFile();

  Lex lex;

  lex.analyzeAFile(toCompileFile);

  LexRecList recList = lex.getRecList();

  GrammarAnalyzer grammar = GrammarAnalyzer(recList);

//  JZSetLoggerLevel(JZ_LOG_DEBUG|JZ_LOG_TRACE);
  uint32 ret = grammar.doAnalyze();
  JZSetLoggerLevel(JZ_LOG_TEST);

  ASSERT_EQ(eGrmErrNoError, ret);

  JZSetLoggerLevel(JZ_LOG_TEST);

}

//basic function ptr declaration
TEST(GrammarAnalyzer, FunctionBasic1)
{
  int argc = 2;
  char argv0[128] = {0},argv1[128] = {0};
  strcpy(argv0,"tester");
  strcpy(argv1,"./test/GrammarSample/function_sample_1");
  char* argv[2] = {argv0,argv1};

	//analyze command line input
	CmdInputFactor::getInstance()->analyze(argc, argv);

	//now begin to analyze the files input from command line
	string toCompileFile = CmdInputFactor::getInstance()->getNextFile();

  Lex lex;

  lex.analyzeAFile(toCompileFile);

  LexRecList recList = lex.getRecList();

  GrammarAnalyzer grammar = GrammarAnalyzer(recList);

  JZSetLoggerLevel(JZ_LOG_DEBUG|JZ_LOG_TRACE);
  uint32 ret = grammar.doAnalyze();

  JZSetLoggerLevel(JZ_LOG_TEST);
  ASSERT_EQ(eGrmErrNoError, ret);

}

<commit_msg>turn off debug<commit_after>#include <gtest/gtest.h>
#include "Lex.h"
#include "CmdInputFactor.h"
#include "GrammarAnalyzer.h"
#include "JZLogger.h"

//basic function declaration
TEST(GrammarAnalyzer, FunctionBasic0)
{
  int argc = 2;
  char argv0[128] = {0},argv1[128] = {0};
  strcpy(argv0,"tester");
  strcpy(argv1,"./test/GrammarSample/function_sample_0");
  char* argv[2] = {argv0,argv1};

	//analyze command line input
	CmdInputFactor::getInstance()->analyze(argc, argv);

	//now begin to analyze the files input from command line
	string toCompileFile = CmdInputFactor::getInstance()->getNextFile();

  Lex lex;

  lex.analyzeAFile(toCompileFile);

  LexRecList recList = lex.getRecList();

  GrammarAnalyzer grammar = GrammarAnalyzer(recList);

//  JZSetLoggerLevel(JZ_LOG_DEBUG|JZ_LOG_TRACE);
  uint32 ret = grammar.doAnalyze();
  JZSetLoggerLevel(JZ_LOG_TEST);

  ASSERT_EQ(eGrmErrNoError, ret);

  JZSetLoggerLevel(JZ_LOG_TEST);

}

//basic function ptr declaration
TEST(GrammarAnalyzer, FunctionBasic1)
{
  int argc = 2;
  char argv0[128] = {0},argv1[128] = {0};
  strcpy(argv0,"tester");
  strcpy(argv1,"./test/GrammarSample/function_sample_1");
  char* argv[2] = {argv0,argv1};

	//analyze command line input
	CmdInputFactor::getInstance()->analyze(argc, argv);

	//now begin to analyze the files input from command line
	string toCompileFile = CmdInputFactor::getInstance()->getNextFile();

  Lex lex;

  lex.analyzeAFile(toCompileFile);

  LexRecList recList = lex.getRecList();

  GrammarAnalyzer grammar = GrammarAnalyzer(recList);

  JZSetLoggerLevel(JZ_LOG_TRACE);
  uint32 ret = grammar.doAnalyze();

  JZSetLoggerLevel(JZ_LOG_TEST);
  ASSERT_EQ(eGrmErrNoError, ret);

}

<|endoftext|>


<commit_before>#include "dock.h"
#include "mainwindow.h"
#include "connection.h"
#include "dockmanagerconfig.h"
#include "dockdelegates.h"
#include "controlbar_dockmanager.h"
#include "serialize.h"
#include <ui_controlbarcommon.h>
#include <QScrollBar>
/*#include <ui_controlbarlogs.h>
#include <ui_controlbarplots.h>
#include <ui_controlbartables.h>
#include <ui_controlbargantts.h>*/

DockManager::DockManager (MainWindow * mw, QStringList const & path)
	: DockManagerView(mw), ActionAble(path)
	, m_main_window(mw)
	, m_dockwidget(0)
	, m_control_bar(0)
	, m_model(0)
	, m_config(g_traceServerName)
{
	qDebug("%s", __FUNCTION__);
	resizeColumnToContents(0);

	QString const name = path.join("/");
	DockWidget * const dock = new DockWidget(*this, name, m_main_window);
	dock->setObjectName(name);
	dock->setWindowTitle(name);
	dock->setAllowedAreas(Qt::AllDockWidgetAreas);
	m_main_window->addDockWidget(Qt::BottomDockWidgetArea, dock);
	dock->setAttribute(Qt::WA_DeleteOnClose, false);
	dock->setWidget(this);

	//if (visible)
	//	m_main_window->restoreDockWidget(dock);
	m_dockwidget = dock;

	connect(m_dockwidget, SIGNAL(widgetVisibilityChanged(bool)), m_main_window, SLOT(onDockManagerVisibilityChanged(bool)));
	m_control_bar = new ControlBarCommon();

	connect(header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(onColumnResized(int, int, int)));
	connect(m_dockwidget, SIGNAL(dockClosed()), mw, SLOT(onDockManagerClosed()));
	setAllColumnsShowFocus(false);
	setExpandsOnDoubleClick(false);
	//setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
	//setSizeAdjustPolicy(QAbstractScrollArea::AdjustIgnored);
	//header()->setSectionResizeMode(0, QHeaderView::Interactive);
	header()->setStretchLastSection(false);
	setEditTriggers(QAbstractItemView::NoEditTriggers);
	//setItemDelegateForColumn(e_Column_Close, new CloseButtonDelegate(*this, this));
	setItemDelegateForColumn(e_Column_Close, new CloseButtonDelegate(*this, this));
	setItemDelegateForColumn(e_Column_ControlWidget, new ControlWidgetDelegate(*this, this));
	setStyleSheet("QTreeView::item{ selection-background-color: #FFE7BA } QTreeView::item{ selection-color: #000000 }");
	//horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { border: 1px solid grey; height: 15px; } QScrollBar::handle:horizontal { background: white; min-width: 10px; }");
	/*
	setStyleSheet(QString::fromUtf8("QScrollBar:vertical {
		"    border: 1px solid #999999;"
		"    background:white;"
		"    width:10px;    "
		"    margin: 0px 0px 0px 0px;"
		"}"
		"QScrollBar::handle:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    min-height: 0px;"
		""
		"}"
		"QScrollBar::add-line:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    height: px;"
		"    subcontrol-position: bottom;"
		"    subcontrol-origin: margin;"
		"}"
		"QScrollBar::sub-line:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    height: 0px;"
		"    subcontrol-position: top;"
		"    subcontrol-origin: margin;"
		"}"
		""));
*/
}

void DockManager::loadConfig (QString const & cfgpath)
{
	QString const fname = cfgpath + "/" + g_dockManagerTag;
	DockManagerConfig config2(g_traceServerName);
	if (!::loadConfigTemplate(config2, fname))
	{
		m_config.defaultConfig();
	}
	else
	{
		m_config = config2;
		config2.m_data.root = 0; // @TODO: promyslet.. takle na to urcite zapomenu
	}

	m_model = new DockManagerModel(*this, this, &m_config.m_data);
	setModel(m_model);
	connect(this, SIGNAL(removeCurrentIndex(QModelIndex const &)), this, SLOT(onRemoveCurrentIndex(QModelIndex const &)));
	bool const on = true;
	addActionAble(*this, on, false, true);
}

void DockManager::applyConfig ()
{
	for (size_t i = 0, ie = m_config.m_columns_sizes.size(); i < ie; ++i)
		header()->resizeSection(static_cast<int>(i), m_config.m_columns_sizes[i]);

	if (m_model)
		m_model->syncExpandState(this);
}

void DockManager::saveConfig (QString const & path)
{
	QString const fname = path + "/" + g_dockManagerTag;
	::saveConfigTemplate(m_config, fname);
}

DockManager::~DockManager ()
{
	disconnect(m_dockwidget, SIGNAL(dockClosed()), m_main_window, SLOT(onDockManagerClosed()));
	disconnect(this, SIGNAL(removeCurrentIndex(QModelIndex const &)), this, SLOT(onRemoveCurrentIndex(QModelIndex const &)));
	disconnect(m_dockwidget, SIGNAL(widgetVisibilityChanged(bool)), m_main_window, SLOT(onDockManagerVisibilityChanged(bool)));
	disconnect(header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(onColumnResized(int, int, int)));

	setParent(0);
	m_dockwidget->setWidget(0);
	delete m_dockwidget;
	m_dockwidget= 0;
	removeActionAble(*this);
}

DockWidget * DockManager::mkDockWidget (DockedWidgetBase & dwb, bool visible)
{
	return mkDockWidget(dwb, visible, Qt::BottomDockWidgetArea);
}

DockWidget * DockManager::mkDockWidget (ActionAble & aa, bool visible, Qt::DockWidgetArea area)
{
	qDebug("%s", __FUNCTION__);
	Q_ASSERT(aa.path().size() > 0);

	QString const name = aa.path().join("/");
	DockWidget * const dock = new DockWidget(*this, name, m_main_window);
	dock->setObjectName(name);
	dock->setWindowTitle(name);
	dock->setAllowedAreas(Qt::AllDockWidgetAreas);
	//dock->setWidget(docked_widget); // @NOTE: commented, it is set by caller
	m_main_window->addDockWidget(area, dock);
	dock->setAttribute(Qt::WA_DeleteOnClose, false);

	if (visible)
		m_main_window->restoreDockWidget(dock);
	return dock;
}

void DockManager::onWidgetClosed (DockWidget * w)
{
	qDebug("%s w=%08x", __FUNCTION__, w);
}

QModelIndex DockManager::addActionAble (ActionAble & aa, bool on, bool close_button, bool control_widget)
{
	qDebug("%s aa=%s show=%i", __FUNCTION__, aa.joinedPath().toStdString().c_str(), on);
	QModelIndex const idx = m_model->insertItemWithPath(aa.path(), on);
	QString const & name = aa.joinedPath();
	m_actionables.insert(name, &aa);
	m_model->initData(idx, QVariant(on ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);

	if (close_button)
	{
		QModelIndex const jdx = m_model->index(idx.row(), e_Column_Close, idx.parent());
		openPersistentEditor(jdx);
	}
	if (control_widget)
	{
		QModelIndex const kdx = m_model->index(idx.row(), e_Column_ControlWidget, idx.parent());
		openPersistentEditor(kdx);
	}
	return idx;

}

QModelIndex DockManager::addActionAble (ActionAble & aa, bool on)
{
	return addActionAble(aa, on, true, true);
}

ActionAble const * DockManager::findActionAble (QString const & dst_joined) const
{
	actionables_t::const_iterator it = m_actionables.find(dst_joined);
	if (it != m_actionables.end() && it.key() == dst_joined)
		return *it;
	return 0;
}
ActionAble * DockManager::findActionAble (QString const & dst_joined)
{
	actionables_t::iterator it = m_actionables.find(dst_joined);
	if (it != m_actionables.end() && it.key() == dst_joined)
		return *it;
	return 0;
}

void DockManager::removeActionAble (ActionAble & aa)
{
	qDebug("%s aa=%s", __FUNCTION__, aa.joinedPath().toStdString().c_str());
	actionables_t::iterator it = m_actionables.find(aa.joinedPath());
	if (it != m_actionables.end() && it.key() == aa.joinedPath())
	{
		QModelIndex const idx = m_model->testItemWithPath(aa.path());
		if (idx.isValid())
			for (int j = 1; j < e_max_dockmgr_column; ++j)
				closePersistentEditor(m_model->index(idx.row(), j, idx.parent()));
		m_actionables.erase(it);
	}
}

void DockManager::onColumnResized (int idx, int , int new_size)
{
	if (idx < 0) return;
	size_t const curr_sz = m_config.m_columns_sizes.size();
	if (idx < curr_sz)
	{
		//qDebug("%s this=0x%08x hsize[%i]=%i", __FUNCTION__, this, idx, new_size);
	}
	else
	{
		m_config.m_columns_sizes.resize(idx + 1);
		for (size_t i = curr_sz; i < idx + 1; ++i)
			m_config.m_columns_sizes[i] = 32;
	}
	m_config.m_columns_sizes[idx] = new_size;
}

bool DockManager::handleAction (Action * a, E_ActionHandleType sync)
{
	QStringList const & src_path = a->m_src_path;
	QStringList const & dst_path = a->m_dst_path;
	QStringList const & my_addr = path();

	if (dst_path.size() == 0)
	{
		qWarning("DockManager::handleAction empty dst");
		return false;
	}

	Q_ASSERT(my_addr.size() == 1);
	int const lvl = dst_path.indexOf(my_addr.at(0), a->m_dst_curr_level);
	if (lvl == -1)
	{
		qWarning("DockManager::handleAction message not for me");
		return false;
	}
	else if (lvl == dst_path.size() - 1)
	{
		// message just for me! gr8!
		a->m_dst_curr_level = lvl;
		a->m_dst = this;
		return true;
	}
	else
	{
		// message for my children
		a->m_dst_curr_level = lvl + 1;

		if (a->m_dst_curr_level >= 0 && a->m_dst_curr_level < dst_path.size())
		{
			QString const dst_joined = dst_path.join("/");
			actionables_t::iterator it = m_actionables.find(dst_joined);
			if (it != m_actionables.end() && it.key() == dst_joined)
			{
				qDebug("delivering action to: %s", dst_joined.toStdString().c_str());
				ActionAble * const next_hop =  it.value();
				next_hop->handleAction(a, sync); //@NOTE: e_Close can invalidate iterator
			}
			else
			{
				//@TODO: find least common subpath
			}
		}
		else
		{
			qWarning("DockManager::handleAction hmm? what?");
		}
	}
	return false;
}

void DockManager::onCloseButton ()
{
	QVariant v = QObject::sender()->property("idx");
	if (v.canConvert<QModelIndex>())
	{
		QModelIndex const idx = v.value<QModelIndex>();
		if (TreeModel<DockedInfo>::node_t * const n = m_model->getItemFromIndex(idx))
		{
			QStringList const & dst_path = n->data.m_path;
			Action a;
			a.m_type = e_Close;
			a.m_src_path = path();
			a.m_src = this;
			a.m_dst_path = dst_path;
			handleAction(&a, e_Sync);
		}
	}
}

void DockManager::onRemoveCurrentIndex (QModelIndex const & idx)
{
	//model()->removeRows(idx.row(), 1, idx.parent());
}
<commit_msg>* control widget init dock area<commit_after>#include "dock.h"
#include "mainwindow.h"
#include "connection.h"
#include "dockmanagerconfig.h"
#include "dockdelegates.h"
#include "controlbar_dockmanager.h"
#include "serialize.h"
#include <ui_controlbarcommon.h>
#include <QScrollBar>
/*#include <ui_controlbarlogs.h>
#include <ui_controlbarplots.h>
#include <ui_controlbartables.h>
#include <ui_controlbargantts.h>*/

DockManager::DockManager (MainWindow * mw, QStringList const & path)
	: DockManagerView(mw), ActionAble(path)
	, m_main_window(mw)
	, m_dockwidget(0)
	, m_control_bar(0)
	, m_model(0)
	, m_config(g_traceServerName)
{
	qDebug("%s", __FUNCTION__);
	resizeColumnToContents(0);

	QString const name = path.join("/");
	DockWidget * const dock = new DockWidget(*this, name, m_main_window);
	dock->setObjectName(name);
	dock->setWindowTitle(name);
	dock->setAllowedAreas(Qt::AllDockWidgetAreas);
	m_main_window->addDockWidget(Qt::TopDockWidgetArea, dock);
	dock->setAttribute(Qt::WA_DeleteOnClose, false);
	dock->setWidget(this);

	//if (visible)
	//	m_main_window->restoreDockWidget(dock);
	m_dockwidget = dock;

	connect(m_dockwidget, SIGNAL(widgetVisibilityChanged(bool)), m_main_window, SLOT(onDockManagerVisibilityChanged(bool)));
	m_control_bar = new ControlBarCommon();

	connect(header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(onColumnResized(int, int, int)));
	connect(m_dockwidget, SIGNAL(dockClosed()), mw, SLOT(onDockManagerClosed()));
	setAllColumnsShowFocus(false);
	setExpandsOnDoubleClick(false);
	//setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
	//setSizeAdjustPolicy(QAbstractScrollArea::AdjustIgnored);
	//header()->setSectionResizeMode(0, QHeaderView::Interactive);
	header()->setStretchLastSection(false);
	setEditTriggers(QAbstractItemView::NoEditTriggers);
	//setItemDelegateForColumn(e_Column_Close, new CloseButtonDelegate(*this, this));
	setItemDelegateForColumn(e_Column_Close, new CloseButtonDelegate(*this, this));
	setItemDelegateForColumn(e_Column_ControlWidget, new ControlWidgetDelegate(*this, this));
	setStyleSheet("QTreeView::item{ selection-background-color: #FFE7BA } QTreeView::item{ selection-color: #000000 }");
	//horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { border: 1px solid grey; height: 15px; } QScrollBar::handle:horizontal { background: white; min-width: 10px; }");
	/*
	setStyleSheet(QString::fromUtf8("QScrollBar:vertical {
		"    border: 1px solid #999999;"
		"    background:white;"
		"    width:10px;    "
		"    margin: 0px 0px 0px 0px;"
		"}"
		"QScrollBar::handle:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    min-height: 0px;"
		""
		"}"
		"QScrollBar::add-line:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    height: px;"
		"    subcontrol-position: bottom;"
		"    subcontrol-origin: margin;"
		"}"
		"QScrollBar::sub-line:vertical {"
		"    background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
		"    stop: 0  rgb(32, 47, 130), stop: 0.5 rgb(32, 47, 130),  stop:1 rgb(32, 47, 130));"
		"    height: 0px;"
		"    subcontrol-position: top;"
		"    subcontrol-origin: margin;"
		"}"
		""));
*/
}

void DockManager::loadConfig (QString const & cfgpath)
{
	QString const fname = cfgpath + "/" + g_dockManagerTag;
	DockManagerConfig config2(g_traceServerName);
	if (!::loadConfigTemplate(config2, fname))
	{
		m_config.defaultConfig();
	}
	else
	{
		m_config = config2;
		config2.m_data.root = 0; // @TODO: promyslet.. takle na to urcite zapomenu
	}

	m_model = new DockManagerModel(*this, this, &m_config.m_data);
	setModel(m_model);
	connect(this, SIGNAL(removeCurrentIndex(QModelIndex const &)), this, SLOT(onRemoveCurrentIndex(QModelIndex const &)));
	bool const on = true;
	addActionAble(*this, on, false, true);
}

void DockManager::applyConfig ()
{
	for (size_t i = 0, ie = m_config.m_columns_sizes.size(); i < ie; ++i)
		header()->resizeSection(static_cast<int>(i), m_config.m_columns_sizes[i]);

	if (m_model)
		m_model->syncExpandState(this);
}

void DockManager::saveConfig (QString const & path)
{
	QString const fname = path + "/" + g_dockManagerTag;
	::saveConfigTemplate(m_config, fname);
}

DockManager::~DockManager ()
{
	disconnect(m_dockwidget, SIGNAL(dockClosed()), m_main_window, SLOT(onDockManagerClosed()));
	disconnect(this, SIGNAL(removeCurrentIndex(QModelIndex const &)), this, SLOT(onRemoveCurrentIndex(QModelIndex const &)));
	disconnect(m_dockwidget, SIGNAL(widgetVisibilityChanged(bool)), m_main_window, SLOT(onDockManagerVisibilityChanged(bool)));
	disconnect(header(), SIGNAL(sectionResized(int, int, int)), this, SLOT(onColumnResized(int, int, int)));

	setParent(0);
	m_dockwidget->setWidget(0);
	delete m_dockwidget;
	m_dockwidget= 0;
	removeActionAble(*this);
}

DockWidget * DockManager::mkDockWidget (DockedWidgetBase & dwb, bool visible)
{
	return mkDockWidget(dwb, visible, Qt::BottomDockWidgetArea);
}

DockWidget * DockManager::mkDockWidget (ActionAble & aa, bool visible, Qt::DockWidgetArea area)
{
	qDebug("%s", __FUNCTION__);
	Q_ASSERT(aa.path().size() > 0);

	QString const name = aa.path().join("/");
	DockWidget * const dock = new DockWidget(*this, name, m_main_window);
	dock->setObjectName(name);
	dock->setWindowTitle(name);
	dock->setAllowedAreas(Qt::AllDockWidgetAreas);
	//dock->setWidget(docked_widget); // @NOTE: commented, it is set by caller
	m_main_window->addDockWidget(area, dock);
	dock->setAttribute(Qt::WA_DeleteOnClose, false);

	if (visible)
		m_main_window->restoreDockWidget(dock);
	return dock;
}

void DockManager::onWidgetClosed (DockWidget * w)
{
	qDebug("%s w=%08x", __FUNCTION__, w);
}

QModelIndex DockManager::addActionAble (ActionAble & aa, bool on, bool close_button, bool control_widget)
{
	qDebug("%s aa=%s show=%i", __FUNCTION__, aa.joinedPath().toStdString().c_str(), on);
	QModelIndex const idx = m_model->insertItemWithPath(aa.path(), on);
	QString const & name = aa.joinedPath();
	m_actionables.insert(name, &aa);
	m_model->initData(idx, QVariant(on ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);

	if (close_button)
	{
		QModelIndex const jdx = m_model->index(idx.row(), e_Column_Close, idx.parent());
		openPersistentEditor(jdx);
	}
	if (control_widget)
	{
		QModelIndex const kdx = m_model->index(idx.row(), e_Column_ControlWidget, idx.parent());
		openPersistentEditor(kdx);
	}
	return idx;

}

QModelIndex DockManager::addActionAble (ActionAble & aa, bool on)
{
	return addActionAble(aa, on, true, true);
}

ActionAble const * DockManager::findActionAble (QString const & dst_joined) const
{
	actionables_t::const_iterator it = m_actionables.find(dst_joined);
	if (it != m_actionables.end() && it.key() == dst_joined)
		return *it;
	return 0;
}
ActionAble * DockManager::findActionAble (QString const & dst_joined)
{
	actionables_t::iterator it = m_actionables.find(dst_joined);
	if (it != m_actionables.end() && it.key() == dst_joined)
		return *it;
	return 0;
}

void DockManager::removeActionAble (ActionAble & aa)
{
	qDebug("%s aa=%s", __FUNCTION__, aa.joinedPath().toStdString().c_str());
	actionables_t::iterator it = m_actionables.find(aa.joinedPath());
	if (it != m_actionables.end() && it.key() == aa.joinedPath())
	{
		QModelIndex const idx = m_model->testItemWithPath(aa.path());
		if (idx.isValid())
			for (int j = 1; j < e_max_dockmgr_column; ++j)
				closePersistentEditor(m_model->index(idx.row(), j, idx.parent()));
		m_actionables.erase(it);
	}
}

void DockManager::onColumnResized (int idx, int , int new_size)
{
	if (idx < 0) return;
	size_t const curr_sz = m_config.m_columns_sizes.size();
	if (idx < curr_sz)
	{
		//qDebug("%s this=0x%08x hsize[%i]=%i", __FUNCTION__, this, idx, new_size);
	}
	else
	{
		m_config.m_columns_sizes.resize(idx + 1);
		for (size_t i = curr_sz; i < idx + 1; ++i)
			m_config.m_columns_sizes[i] = 32;
	}
	m_config.m_columns_sizes[idx] = new_size;
}

bool DockManager::handleAction (Action * a, E_ActionHandleType sync)
{
	QStringList const & src_path = a->m_src_path;
	QStringList const & dst_path = a->m_dst_path;
	QStringList const & my_addr = path();

	if (dst_path.size() == 0)
	{
		qWarning("DockManager::handleAction empty dst");
		return false;
	}

	Q_ASSERT(my_addr.size() == 1);
	int const lvl = dst_path.indexOf(my_addr.at(0), a->m_dst_curr_level);
	if (lvl == -1)
	{
		qWarning("DockManager::handleAction message not for me");
		return false;
	}
	else if (lvl == dst_path.size() - 1)
	{
		// message just for me! gr8!
		a->m_dst_curr_level = lvl;
		a->m_dst = this;
		return true;
	}
	else
	{
		// message for my children
		a->m_dst_curr_level = lvl + 1;

		if (a->m_dst_curr_level >= 0 && a->m_dst_curr_level < dst_path.size())
		{
			QString const dst_joined = dst_path.join("/");
			actionables_t::iterator it = m_actionables.find(dst_joined);
			if (it != m_actionables.end() && it.key() == dst_joined)
			{
				qDebug("delivering action to: %s", dst_joined.toStdString().c_str());
				ActionAble * const next_hop =  it.value();
				next_hop->handleAction(a, sync); //@NOTE: e_Close can invalidate iterator
			}
			else
			{
				//@TODO: find least common subpath
			}
		}
		else
		{
			qWarning("DockManager::handleAction hmm? what?");
		}
	}
	return false;
}

void DockManager::onCloseButton ()
{
	QVariant v = QObject::sender()->property("idx");
	if (v.canConvert<QModelIndex>())
	{
		QModelIndex const idx = v.value<QModelIndex>();
		if (TreeModel<DockedInfo>::node_t * const n = m_model->getItemFromIndex(idx))
		{
			QStringList const & dst_path = n->data.m_path;
			Action a;
			a.m_type = e_Close;
			a.m_src_path = path();
			a.m_src = this;
			a.m_dst_path = dst_path;
			handleAction(&a, e_Sync);
		}
	}
}

void DockManager::onRemoveCurrentIndex (QModelIndex const & idx)
{
	//model()->removeRows(idx.row(), 1, idx.parent());
}
<|endoftext|>


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

#define NX 50
#define NY 50
#define NZ 50

#define SX 34
#define SY 34
#define SZ 34

#define T_MAX 8000

typedef double Real;

const Real Fu = 1.0/86400, Fv = 6.0/86400, Fe = 1.0/900, Du = 0.1*2.3e-9, Dv = 12.2e-11;
const Real dt = 0*200, dx = 0.001;

Real U[NX][NY][NZ], V[NX][NY][NZ];
Real U_other[NX][NY][NZ], V_other[NX][NY][NZ];
int global_clock;

Real Uwx[T_MAX][2][SY][SZ], Uwy[T_MAX][SX][2][SZ], Uwz[T_MAX][SX][SY][2];
Real Vwx[T_MAX][2][SY][SZ], Vwy[T_MAX][SX][2][SZ], Vwz[T_MAX][SX][SY][2];

Real sU0[SX][SY][SZ], sV0[SX][SY][SZ];
Real sU[SX][SY][SZ], sV[SX][SY][SZ];

void fill_initial_condition() {
  global_clock=0;
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        U[x][y][z] = 1;
        V[x][y][z] = 0;
      }
    }
  }
  int bx = std::max(NX/4,NX/2-8),  ex = std::min(3*NX/4+1,NX/2+8);
  int by = std::max(NY/4,NY/2-8),  ey = std::min(3*NY/4+1,NY/2+8);
  int bz = std::max(NZ/4,NZ/2-8),  ez = std::min(3*NZ/4+1,NZ/2+8);
  for (int x=bx;x<ex;++x){
    for (int y=by;y<ey;++y){
      for (int z=bz;z<ez;++z){
        U[x][y][z] = 0.5;
        V[x][y][z] = 0.25+0.1*sin(x+sqrt(y)+cos(z));
      }
    }
  }
}

inline Real periodic(Real ar[NX][NY][NZ],int x, int y, int z) {
    x = ((x+100*NX)%NX+NX)%NX;
    y = ((y+100*NY)%NY+NY)%NY;
    z = ((z+100*NZ)%NZ+NZ)%NZ;
    //x = (x+NX)%NX;
    //y = (y+NY)%NY;
    //z = (z+NZ)%NZ;
  return ar[x][y][z];
}

void naive_proceed() {
  ++global_clock;

  auto lap = [](Real ar[NX][NY][NZ],int x, int y, int z) {
    auto ret = periodic(ar, x-1, y, z) + periodic(ar, x+1, y, z)
    + periodic(ar, x, y-1, z) + periodic(ar, x, y+1, z)
    + periodic(ar, x, y, z-1) + periodic(ar, x, y, z+1)
    - 6*ar[x][y][z];
    return ret / dx / dx;
  };

#pragma omp parallel for collapse(2)
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        auto u = U[x][y][z],  v = V[x][y][z];
        auto du_dt = -Fe * u*v*v + Fu*(1-u) + Du * lap(U,x,y,z);
        auto dv_dt =  Fe * u*v*v - Fv*v     + Dv * lap(V,x,y,z);
        U_other[x][y][z] = U[x][y][z] + dt*du_dt;
        V_other[x][y][z] = V[x][y][z] + dt*dv_dt;
      }
    }
  }

  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        U[x][y][z]=U_other[x][y][z];
      }
    }
  }
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        V[x][y][z]=V_other[x][y][z];
      }
    }
  }
}

void get_solution_at(int t, int x, int y, int z, Real &u, Real &v) {
  if(global_clock > t) fill_initial_condition();
  while(global_clock < t) naive_proceed();
  u = periodic(U,x,y,z);
  v = periodic(V,x,y,z);
}

int main () {

  fill_initial_condition();
  for(int x=0;x<SX;++x) {
    for(int y=0;y<SY;++y) {
      for(int z=0;z<SZ;++z) {
        double u,v; get_solution_at(0,x,y,z, u,v);
        sU0[x][y][z]=u;
        sV0[x][y][z]=v;
      }
    }
  }

  std::cerr << "Setting up wall values..." << std::endl;
  for(int t = 0;t<T_MAX;++t){
    for(int x=SX-2;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwx[t][x-(SX-2)][y][z] = u;
          Vwx[t][x-(SX-2)][y][z] = v;
        }
      }
    }

    for(int x=0;x<SX;++x) {
      for(int y=SY-2;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwy[t][x][y-(SY-2)][z] = u;
          Vwy[t][x][y-(SY-2)][z] = v;
        }
      }
    }

    for(int x=0;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=SZ-2;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwz[t][x][y][z-(SZ-2)] = u;
          Vwz[t][x][y][z-(SZ-2)] = v;
        }
      }
    }
  }

  std::cerr << "Carrying out simulation..." << std::endl;
  // set initial condition
  for(int x=0;x<SX;++x) {
    for(int y=0;y<SY;++y) {
      for(int z=0;z<SZ;++z) {
        sU[x][y][z]=sU0[x][y][z];
        sV[x][y][z]=sV0[x][y][z];
      }
    }
  }

  for(int t = 0; t < T_MAX; ++t){
    // load communication values
#pragma omp parallel for collapse(3)
    for(int x=SX-2;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          sU[x][y][z] = Uwx[t][x-(SX-2)][y][z];
          sV[x][y][z] = Vwx[t][x-(SX-2)][y][z];
        }
      }
    }

#pragma omp parallel for collapse(3)
    for(int x=0;x<SX-2;++x) {
      for(int y=SY-2;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          sU[x][y][z] = Uwy[t][x][y-(SY-2)][z];
          sV[x][y][z] = Vwy[t][x][y-(SY-2)][z];
        }
      }
    }

#pragma omp parallel for collapse(3)
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=SZ-2;z<SZ;++z) {
          sU[x][y][z] = Uwz[t][x][y][z-(SZ-2)];
          sV[x][y][z] = Vwz[t][x][y][z-(SZ-2)];
        }
      }
    }

    /*
    std::cerr << "stat" <<std::endl;
    for(int y=0;y<SY-2;++y) {
      for(int z=0;z<SZ-2;++z) {
        //        double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
        std::cerr << int(9.999*sU[SX/2][y][z]);
      }
      std::cerr <<std::endl;
    }
    std::cerr << "sol" <<std::endl;
    for(int y=0;y<SY-2;++y) {
      for(int z=0;z<SZ-2;++z) {
        int x=SX/2;
        double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
        std::cerr << int(9.999*u);
      }
      std::cerr <<std::endl;
      }*/

    // destructively update the state
    const auto lap = [](Real ar[SX][SY][SZ],int x, int y, int z) {
      auto ret = ar[x][y+1][z+1] + ar[x+2][y+1][z+1]
      + ar[x+1][y][z+1] + ar[x+1][y+2][z+1]
      + ar[x+1][y+1][z] + ar[x+1][y+1][z+2]
      - 6*ar[x+1][y+1][z+1];
      return ret / dx / dx;
    };

#pragma omp parallel for collapse(2)
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=0;z<SZ-2;++z) {
          Real u=sU[x+1][y+1][z+1] ;
          Real v=sV[x+1][y+1][z+1] ;

          auto du_dt = -Fe * u*v*v + Fu*(1-u) + Du * lap(sU,x,y,z);
          auto dv_dt =  Fe * u*v*v - Fv*v     + Dv * lap(sV,x,y,z);
          sU[x][y][z] = u+dt*du_dt;
          sV[x][y][z] = v+dt*dv_dt;
        }
      }
    }
  }

  {
    const int t = T_MAX;
    double num=0,den=0;
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=0;z<SZ-2;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          num += std::abs(u-sU[x][y][z]);
          den += 1;
        }
      }
    }
    std::cout << "average error: " << (num/den) << std::endl;
  }

}

<commit_msg>Correct parallelization with double buffering<commit_after>#include <cmath>
#include <unistd.h>
#include <iostream>
#include <sstream>

#define NX 50
#define NY 50
#define NZ 50

#define SX 34
#define SY 34
#define SZ 34

#define T_MAX 1000

typedef double Real;

const Real Fu = 1.0/86400, Fv = 6.0/86400, Fe = 1.0/900, Du = 0.1*2.3e-9, Dv = 12.2e-11;
const Real dt = 0*200, dx = 0.001;

Real U[NX][NY][NZ], V[NX][NY][NZ];
Real U_other[NX][NY][NZ], V_other[NX][NY][NZ];
int global_clock;

Real Uwx[T_MAX][2][SY][SZ], Uwy[T_MAX][SX][2][SZ], Uwz[T_MAX][SX][SY][2];
Real Vwx[T_MAX][2][SY][SZ], Vwy[T_MAX][SX][2][SZ], Vwz[T_MAX][SX][SY][2];

Real sU0[SX][SY][SZ], sV0[SX][SY][SZ];
Real sU[SX][SY][SZ], sV[SX][SY][SZ];
Real sU_1[SX][SY][SZ], sV_1[SX][SY][SZ];

void fill_initial_condition() {
  global_clock=0;
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        U[x][y][z] = 1;
        V[x][y][z] = 0;
      }
    }
  }
  int bx = std::max(NX/4,NX/2-8),  ex = std::min(3*NX/4+1,NX/2+8);
  int by = std::max(NY/4,NY/2-8),  ey = std::min(3*NY/4+1,NY/2+8);
  int bz = std::max(NZ/4,NZ/2-8),  ez = std::min(3*NZ/4+1,NZ/2+8);
  for (int x=bx;x<ex;++x){
    for (int y=by;y<ey;++y){
      for (int z=bz;z<ez;++z){
        U[x][y][z] = 0.5;
        V[x][y][z] = 0.25+0.1*sin(x+sqrt(y)+cos(z));
      }
    }
  }
}

inline Real periodic(Real ar[NX][NY][NZ],int x, int y, int z) {
    x = ((x+100*NX)%NX+NX)%NX;
    y = ((y+100*NY)%NY+NY)%NY;
    z = ((z+100*NZ)%NZ+NZ)%NZ;
    //x = (x+NX)%NX;
    //y = (y+NY)%NY;
    //z = (z+NZ)%NZ;
  return ar[x][y][z];
}

void naive_proceed() {
  ++global_clock;

  auto lap = [](Real ar[NX][NY][NZ],int x, int y, int z) {
    auto ret = periodic(ar, x-1, y, z) + periodic(ar, x+1, y, z)
    + periodic(ar, x, y-1, z) + periodic(ar, x, y+1, z)
    + periodic(ar, x, y, z-1) + periodic(ar, x, y, z+1)
    - 6*ar[x][y][z];
    return ret / dx / dx;
  };

#pragma omp parallel for collapse(2)
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        auto u = U[x][y][z],  v = V[x][y][z];
        auto du_dt = -Fe * u*v*v + Fu*(1-u) + Du * lap(U,x,y,z);
        auto dv_dt =  Fe * u*v*v - Fv*v     + Dv * lap(V,x,y,z);
        U_other[x][y][z] = U[x][y][z] + dt*du_dt;
        V_other[x][y][z] = V[x][y][z] + dt*dv_dt;
      }
    }
  }

  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        U[x][y][z]=U_other[x][y][z];
      }
    }
  }
  for (int x=0;x<NX;++x) {
    for (int y=0;y<NY;++y) {
      for (int z=0;z<NZ;++z) {
        V[x][y][z]=V_other[x][y][z];
      }
    }
  }
}

void get_solution_at(int t, int x, int y, int z, Real &u, Real &v) {
  if(global_clock > t) fill_initial_condition();
  while(global_clock < t) naive_proceed();
  u = periodic(U,x,y,z);
  v = periodic(V,x,y,z);
}

int main () {

  fill_initial_condition();
  for(int x=0;x<SX;++x) {
    for(int y=0;y<SY;++y) {
      for(int z=0;z<SZ;++z) {
        double u,v; get_solution_at(0,x,y,z, u,v);
        sU0[x][y][z]=u;
        sV0[x][y][z]=v;
      }
    }
  }

  std::cerr << "Setting up wall values..." << std::endl;
  for(int t = 0;t<T_MAX;++t){
    for(int x=SX-2;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwx[t][x-(SX-2)][y][z] = u;
          Vwx[t][x-(SX-2)][y][z] = v;
        }
      }
    }

    for(int x=0;x<SX;++x) {
      for(int y=SY-2;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwy[t][x][y-(SY-2)][z] = u;
          Vwy[t][x][y-(SY-2)][z] = v;
        }
      }
    }

    for(int x=0;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=SZ-2;z<SZ;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          Uwz[t][x][y][z-(SZ-2)] = u;
          Vwz[t][x][y][z-(SZ-2)] = v;
        }
      }
    }
  }

  std::cerr << "Carrying out simulation..." << std::endl;
  // set initial condition
  for(int x=0;x<SX;++x) {
    for(int y=0;y<SY;++y) {
      for(int z=0;z<SZ;++z) {
        sU[x][y][z]=sU0[x][y][z];
        sV[x][y][z]=sV0[x][y][z];
      }
    }
  }

  for(int t = 0; t < T_MAX; ++t){
    // load communication values
#pragma omp parallel for collapse(3)
    for(int x=SX-2;x<SX;++x) {
      for(int y=0;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          sU[x][y][z] = Uwx[t][x-(SX-2)][y][z];
          sV[x][y][z] = Vwx[t][x-(SX-2)][y][z];
        }
      }
    }

#pragma omp parallel for collapse(3)
    for(int x=0;x<SX-2;++x) {
      for(int y=SY-2;y<SY;++y) {
        for(int z=0;z<SZ;++z) {
          sU[x][y][z] = Uwy[t][x][y-(SY-2)][z];
          sV[x][y][z] = Vwy[t][x][y-(SY-2)][z];
        }
      }
    }

#pragma omp parallel for collapse(3)
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=SZ-2;z<SZ;++z) {
          sU[x][y][z] = Uwz[t][x][y][z-(SZ-2)];
          sV[x][y][z] = Vwz[t][x][y][z-(SZ-2)];
        }
      }
    }

    // destructively update the state
    const auto lap = [](Real ar[SX][SY][SZ],int x, int y, int z) {
      auto ret = ar[x][y+1][z+1] + ar[x+2][y+1][z+1]
      + ar[x+1][y][z+1] + ar[x+1][y+2][z+1]
      + ar[x+1][y+1][z] + ar[x+1][y+1][z+2]
      - 6*ar[x+1][y+1][z+1];
      return ret / dx / dx;
    };

#pragma omp parallel for collapse(2)
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=0;z<SZ-2;++z) {
          Real u=sU[x+1][y+1][z+1] ;
          Real v=sV[x+1][y+1][z+1] ;

          auto du_dt = -Fe * u*v*v + Fu*(1-u) + Du * lap(sU,x,y,z);
          auto dv_dt =  Fe * u*v*v - Fv*v     + Dv * lap(sV,x,y,z);
          sU_1[x][y][z] = u+dt*du_dt;
          sV_1[x][y][z] = v+dt*dv_dt;
        }
      }
    }
#pragma omp parallel for collapse(2)
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=0;z<SZ-2;++z) {
          sU[x][y][z] = sU_1[x][y][z];
          sV[x][y][z] = sV_1[x][y][z];
        }
      }
    }
  }

  {
    const int t = T_MAX;
    double num=0,den=0;
    for(int x=0;x<SX-2;++x) {
      for(int y=0;y<SY-2;++y) {
        for(int z=0;z<SZ-2;++z) {
          double u,v; get_solution_at(t,x+t,y+t,z+t, u,v);
          num += std::abs(u-sU[x][y][z]);
          den += 1;
        }
      }
    }
    std::cout << "average error: " << (num/den) << std::endl;
  }

}
<|endoftext|>


<commit_before>#ifndef __STRUCT_HPP
#define __STRUCT_HPP

#include <typeinfo>
#include <vector>
#include <boost/shared_ptr.hpp>

#include "attribute.hpp"
#include "meta_struct.hpp"

//! Shared pointer to meta struct.
typedef boost::shared_ptr<MetaStruct> PMetaStruct;

/*!
 * A structure instance. This class serves to creates instance of a
 * MetaStruct.
 */
class Struct {
public:
  //! Create structure from a metaclass description.
  Struct(PMetaStruct meta_struct)
	: meta_struct(meta_struct) {
	for (std::vector<MetaAttribute>::const_iterator
		   meta_attribute = meta_struct->meta_attributes.begin();
		 meta_attribute != meta_struct->meta_attributes.end();
		 meta_attribute++) {
	  // push back a copy of the default value
	  attributes.push_back(Attribute(meta_attribute->default_value));
	};
  };
  //! Copy constructor.
  Struct(const Struct & struc)
	: meta_struct(struc.meta_struct), attributes(struc.attributes) {};
  //! Get the value of an attribute.
  template<typename ValueType> ValueType & get_attr(const std::string & name) {
	std::map<std::string, unsigned int>::iterator index = meta_struct->index_map.find(name);
	if (index != meta_struct->index_map.end()) {
	  try
	  {
	    return boost::any_cast<ValueType &>(attributes[index->second]);
	  }
	  catch (const boost::bad_any_cast &)
	  {
		throw type_error("Type mismatch on attribute \"" + name + "\" (required " + std::string(attributes[index->second].type().name()) + " but got " + std::string(typeid(ValueType).name()) + ").");
	  }
	} else {
	  throw name_error("Struct has no attribute \"" + name + "\".");
	};
  };
private:
  PMetaStruct meta_struct;
  std::vector<Attribute> attributes;
};

#endif

<commit_msg>cffi: simplified struct code<commit_after>#ifndef __STRUCT_HPP
#define __STRUCT_HPP

#include <typeinfo>
#include <vector>
#include <boost/foreach.hpp>

#include "attribute.hpp"
#include "meta_struct.hpp"

/*!
 * A structure instance. This class serves to create an instance of a
 * MetaStruct.
 */
class Struct {
public:
  //! Create structure from a metaclass description.
  Struct(PMetaStruct meta_struct)
	: meta_struct(meta_struct)
  {
	BOOST_FOREACH(const MetaAttribute & meta_attribute,
				  meta_struct->meta_attributes) {
	  // push back a copy of the default value
	  attributes.push_back(Attribute(meta_attribute.default_value));
	};
  }
  //! Copy constructor.
  Struct(const Struct & struc)
	: meta_struct(struc.meta_struct), attributes(struc.attributes) {};
  //! Get reference to the value of an attribute.
  template<typename ValueType> ValueType & get_attr(const std::string & name)
  {
	std::map<std::string, unsigned int>::iterator index;

	// search name in meta struct index
	index = meta_struct->index_map.find(name);

	if (index != meta_struct->index_map.end()) {
	  // found, so return attribute as requested type
	  try
		{
		  return boost::any_cast<ValueType &>(attributes[index->second]);
		}
	  catch (const boost::bad_any_cast &)
		{
		  // could not get attribute in requested type, so throw exception
		  throw type_error("Type mismatch on attribute \"" + name + "\" (required " + std::string(attributes[index->second].type().name()) + " but got " + std::string(typeid(ValueType).name()) + ").");
		}
	} else {
	  // not found, so throw an exception
	  throw name_error("Struct has no attribute \"" + name + "\".");
	};
  };
private:
  //! Metaclass information (list of attribute types, default values, ...).
  PMetaStruct meta_struct;
  //! List of attribute values.
  std::vector<Attribute> attributes;
};

#endif // __STRUCT_HPP
<|endoftext|>


<commit_before>#include "Platform.hpp"
#include "SimpleProteinEnvironment.hpp"
namespace Elysia {
/*
//Example of a pair
namespace std {
template <class T, class U> class pair {public:
 pair (const T&f, const U&s) {first=f;second=s;}
 T first;
 U second;
};}
*/

//Initialize the main-zone-list by reading the genes and creating 1 zone per gene from Genome (and simplify)
ProteinEnvironment& SimpleProteinEnvironment::initialize(const Elysia::Genome::Genome&genes){
    //Zones start out as representing 1 gene (can be overlapping)
    //Since they can represent a collection of genes,
    //They are chopped during the intersection process and overlap regions become new zones
    const Elysia::Genome::Chromosome *fatherMother[2];
    fatherMother[0]=&genes.fathers();
    fatherMother[1]=&genes.mothers();
    //Loop through all the genes
    for (int chromosomeNum=0;chromosomeNum<2;++chromosomeNum) {
       int num_genes=fatherMother[chromosomeNum]->genes_size();
       for (int i=0;i<num_genes;++i) {
          //Define the new zone
          const Elysia::Genome::Gene*gene=&fatherMother[chromosomeNum]->genes(i);
          int num_bounds=gene->bounds_size();
          for (int k=0;k<num_bounds;++k) {
              ProteinZone newZone;
              newZone.mGenes.push_back(*gene);
              int num_proteins=gene->external_proteins_size();
              for (int j=0;j<num_proteins;++j) {
                  const Elysia::Genome::Protein *protein=&gene->external_proteins(j);
                  newZone.mSoup.push_back(ProteinZone::EffectAndDensityPair(protein->protein_code(),protein->density()));
              }
              newZone.mBounds =BoundingBox3f3f(Vector3f(gene->bounds(k).minx(),
                                                        gene->bounds(k).miny(),
                                                        gene->bounds(k).minz()),
                                               Vector3f(gene->bounds(k).maxx(),
                                                        gene->bounds(k).maxy(),
                                                        gene->bounds(k).maxz()));
              mMainZoneList.push_back(newZone);
          }
       }
    }
	zoneIntersection(mMainZoneList);
    return *this;
}

//Find the "specific protein density" total up the protein (given effect)
//Return the magnitude of a given effect.
float SimpleProteinEnvironment::ProteinZone::getSpecificProteinDensity(Elysia::Genome::Effect e){
  float retval=0;
  std::vector< std::pair<Elysia::Genome::Effect,float> >::const_iterator i,ie;
  for (i=mSoup.begin(),ie=mSoup.end();i!=ie;++i) {
  //if the effect in the current iterator matches the desired protein effect passed in as "e", add the float to the return value
        if (i->first==e) retval+=i->second;
  }
  return retval;
}

//Get protein density at a location (given location, and protein effect interested in)
//Return float of the effect's density
float SimpleProteinEnvironment::getProteinDensity(const Vector3f &location, const Elysia::Genome::Effect&effect) {
  float density=0;
  ///loop through all protein zones
  for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
    //if our test point is in the zone
    if (i->getBoundingBox().contains(location)) {
        //then accumulate the matching effect (if present) into final result
        density+=i->getSpecificProteinDensity(effect);
    }
  }
  //and return the result
  return density;
}

//Find all the proteins at a given point (given location)
//Return vector of proteins
std::vector<std::pair<Elysia::Genome::Effect, float> > SimpleProteinEnvironment::getCompleteProteinDensity(const Vector3f& location){
  std::vector<ProteinZone::EffectAndDensityPair >proteins;
  //loop through all the zones
  for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
    //if our test point is in the zone
    if (i->getBoundingBox().contains(location)) {
        //Append the effects (i.e. mSoup) to the end of the returned proteins
        proteins.insert(proteins.end(),i->mSoup.begin(),i->mSoup.end());
    }
  }
  return proteins;
}

//Update ALL the mSoup (densities) for the next timestep, (given the current age)
//Return nothing
// These functions are not ready yet--- we should get LNK errors for them so we know when we're done
//"Complicated" function to update the soup for the next time iteration
void SimpleProteinEnvironment::ProteinZone::updateSoupToNextSoup(const float age){
	//Will write this function last
}

//The area is not equal in any aspect -> not OK
static bool okArea(const BoundingBox3f3f&input) {
  return input.min().x!=input.max().x&&input.min().y!=input.max().y;
}

template <class T> BoundingBox<T> intersect(const BoundingBox<T>&a, const BoundingBox<T>&b) {
   BoundingBox<T> retval(a.min().max(b.min()),a.max().min(b.max()));
   if (retval.diag().x<=0||retval.diag().y<=0) {
      return BoundingBox<T>(retval.min(),retval.min());//null bounding box at min
   }
   return retval;
}

//Combine genes into a single-shared region
 SimpleProteinEnvironment::ProteinZone SimpleProteinEnvironment::combineZone(const SimpleProteinEnvironment::ProteinZone &a, const SimpleProteinEnvironment::ProteinZone&b , const BoundingBox3f3f &bbox) {
   ProteinZone retval;
   retval.mBounds=bbox;
   assert(!a.mSoup.empty()&&!b.mSoup.empty());
   //Combine the genes into a shared, common sized, region
   retval.mGenes.insert(retval.mGenes.end(),a.mGenes.begin(),a.mGenes.end());
   retval.mGenes.insert(retval.mGenes.end(),b.mGenes.begin(),b.mGenes.end());
   return retval;
}

//Relocate a zone to a new box location
SimpleProteinEnvironment::ProteinZone SimpleProteinEnvironment::relocateZone(ProteinZone a, const BoundingBox3f3f &bbox) { //generate a box of type a
   a.mBounds=bbox;
   return a;
}

//Merge 2 zones of same gene type
void SimpleProteinEnvironment::combineZonesFromSameGene(ProteinZone &a, const ProteinZone&b) {
   a.mBounds.mergeIn(b.mBounds);
}

//Combine 2 zones by dividing it up into parts before reassembling them
void SimpleProteinEnvironment::chopZonePair(const ProteinZone &a, const ProteinZone &b, std::vector<ProteinZone> &output) {
    // Assume any combination of 2 zones will results in 9 subsections
    // Figure out using the intersections points how to generate the subsections
    // Subsections of area 0 --> ignore
    // Add subsections of significant areas to the list with the proper gene type
    // Combine subsections of similar gene type horizontally
  ProteinZone ab[2]={a,b};  //combine a and b into a list
  if (!okArea(intersect(ab[0].mBounds,ab[1].mBounds))) {
     output.push_back(a);
     output.push_back(b);
     return;
  }
  float horizedges[4]={ab[0].mBounds.min().x,ab[1].mBounds.min().x,ab[0].mBounds.max().x,ab[1].mBounds.max().x};  //generate list of x bounds
  float vertedges[4]={ab[0].mBounds.min().y,ab[1].mBounds.min().y,ab[0].mBounds.max().y,ab[1].mBounds.max().y};  //generate lsit of y bounds
  std::sort(horizedges+0,horizedges+4);  //Sort the horizontal list left->right (min->max)
  std::sort(vertedges+0,vertedges+4);  //Sort the vertical list top->bottom (min->max)
  bool combinable[3][3][2];
  ProteinZone combiners[3][3][2];
  //Loop through the subsections
  for (int i=0;i<3;++i) {
    for (int j=0;j<3;++j) {
      BoundingBox3f3f newBounds[2];
      //Generate one section 1->9 (corner-to-corner)
      BoundingBox3f3f location(Vector3f(horizedges[i],vertedges[j],a.mBounds.min().z),
                                   Vector3f(horizedges[i+1],vertedges[j+1],a.mBounds.max().z));
      bool valid[2];
      for (int z=0;z<2;++z) {
         //Is it inside a or b?
         valid[z]=okArea(newBounds[z]=intersect(location,ab[z].mBounds));
         combinable[i][j][z]=false;
      }
      if (valid[0]&&valid[1]) { //It is a subsection of A and B
         output.push_back(combineZone(a,b,location));
      } else if (valid[0]) { //It is a subsection of A
         combiners[i][j][0]=relocateZone(ab[0],newBounds[0]);
         combinable[i][j][0]=true;
      } else if (valid[1]) { //It is a subsection of B
         combiners[i][j][0]=relocateZone(ab[1],newBounds[1]);
         combinable[i][j][1]=true;
      }
    }
  }
  //Results in 9 subsections of type A, B and AB

  //Loop through the subsections and determine zones that are neighbors (horizontal)
  for (int z=0;z<2;++z) {
    for (int i=0;i<3;++i) {
      for (int j=0;j<2;++j) {
         if (combinable[i][j][z]&&combinable[i][j+1][z]) {
            combineZonesFromSameGene(combiners[i][j+1][z],combiners[i][j][z]);
            combinable[i][j][z]=false;
         }
       }
    }
  }
  //send back combined zones
  for (int z=0;z<2;++z) {
    for (int i=0;i<3;++i) {
      for (int j=0;j<3;++j) {
         if (combinable[i][j][z]) {
            output.push_back(combiners[i][j][z]);
         }
      }
    }
  }
}

//Split and simplify large zone definitions into smaller component zones for calculations (given list of all zones)
//Return a list of zones (post-split)
void SimpleProteinEnvironment::zoneIntersection(std::vector<ProteinZone> mMainZoneList){
	std::vector<ProteinZone> mLocalZoneList;
	std::vector<ProteinZone> mSwapZoneList;
	mLocalZoneList = mMainZoneList;
	mSwapZoneList = mMainZoneList;
	bool converged=false;
	bool restart=false;

	while (!converged) {
		//Defaults to converged incase for-loop and detection never terminates
    	converged=true;

    	//Loop through zones and check intersection (for row from start-->end)
    	for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
			//(for column from current-row-diagonal + 1 --> end) ==> results in half triangle w/o diagonal
	    	for (std::vector<ProteinZone>::iterator j=i+1,je=mMainZoneList.end();j!=je;++j) {
				if(!restart){
					mLocalZoneList.clear();	//ensure that the list returned is initialized properly
					mSwapZoneList.clear();		//ensure that the list returned is initialized properly
					chopZonePair(*i,*j,mLocalZoneList);
					if(mLocalZoneList.size() == 2){
						if( ((i->mBounds == mLocalZoneList[0].mBounds)  ||
							 (i->mBounds == mLocalZoneList[1].mBounds)) ||
							((j->mBounds == mLocalZoneList[0].mBounds)  ||
							 (j->mBounds == mLocalZoneList[1].mBounds)) ){
							//Technicaly, I only need to look at only i, or j, but the 2nd set it a sanity check
							//No new zones were created
							//-No action
						}else{
							//These are 2 new zones
							//-Create new zones excluding current 2
							//-Append new zones to list
							//-Restart -> Swap
							rebuildZones(i,j,mMainZoneList,mSwapZoneList);
							addZones(mLocalZoneList,mSwapZoneList);
							restart = true;
						}
					}else if ((mLocalZoneList.size() > 2)||(mLocalZoneList.size() == 1)){
						//These are all new zones
						//-Create new zones excluding current 2
						//-Append new zones to list
						//-Restart -> Swap
						rebuildZones(i,j,mMainZoneList,mSwapZoneList);
						addZones(mLocalZoneList,mSwapZoneList);
						restart = true;
					}else{
						//Serious error... should not be 0 or fewer
					}
				}//end if
    		}//end for
    	}//end for

		if(restart){
			mMainZoneList.swap(mSwapZoneList);
			converged=false;
		}

	}//end while
}

//Rebuild the zone list such that it exclude the 2 zones currently in question
//This allows us to throw out the 2 zones and add their replacements
void SimpleProteinEnvironment::rebuildZones(std::vector<ProteinZone>::const_iterator a,std::vector<ProteinZone>::const_iterator b, const std::vector<ProteinZone> &input, std::vector<ProteinZone> &output) {
    // Create a new list excluding the current 2 zones
	for (std::vector<ProteinZone>::const_iterator i=input.begin(),ie=input.end();i!=ie;++i) {
		if( (i != a)&&(i != b) ){
			output.push_back(*i);
		}
	}
	return;
}

//Zone management functions to add zones to the main list (given sub-list, and main-list)
//Return new main-list
void SimpleProteinEnvironment::addZones( const std::vector<ProteinZone> &mSubZoneList,
                                        std::vector<ProteinZone> &mMainZoneList){
    //Append all the zones in the sub-list to the main-list
	for (std::vector<ProteinZone>::const_iterator i=mSubZoneList.begin(),ie=mSubZoneList.end();i!=ie;++i) {
		mMainZoneList.push_back(*i);
	}
	return;
}

//Zone management functions to remove zones from the main list (given sub-list, and main-list)
//Return new main-list
void SimpleProteinEnvironment::removeZones(  std::vector<ProteinZone> mSubZoneList,
                                            std::vector<ProteinZone> mMainZoneList){
    //Find and remove all matching entries in the sub-list out of the main-list
}

//Function to find the zone that a single point reside in (given point, and zone list)
//Return THE zone from the list that is inside the point, or fail
SimpleProteinEnvironment::ProteinZone &SimpleProteinEnvironment::resideInZones(   const Vector3f queryPoint,
                                                        std::vector<ProteinZone> mMainZoneList){
	int i;
	static ProteinZone myFail;
	size_t numMainZones=mMainZoneList.size();

	for(size_t i=0;i<mMainZoneList.size();++i){
		if (mMainZoneList[i].mBounds.contains(queryPoint)) {
			return mMainZoneList[i];
		}
	}

	return myFail;
}

const Elysia::Genome::Gene& SimpleProteinEnvironment::retrieveGene(const Vector3f &location, const Elysia::Genome::Effect&effect){
  assert(0);
  //FIXME actually look up the responsible gene from the set of "active" genes causing the effect to be spilled at this location
  static Elysia::Genome::Gene retval;
  return retval;
}

SimpleProteinEnvironment::~SimpleProteinEnvironment(){
}

}
<commit_msg>fixed infinite loop error<commit_after>#include "Platform.hpp"
#include "SimpleProteinEnvironment.hpp"
namespace Elysia {
/*
//Example of a pair
namespace std {
template <class T, class U> class pair {public:
 pair (const T&f, const U&s) {first=f;second=s;}
 T first;
 U second;
};}
*/

//Initialize the main-zone-list by reading the genes and creating 1 zone per gene from Genome (and simplify)
ProteinEnvironment& SimpleProteinEnvironment::initialize(const Elysia::Genome::Genome&genes){
    //Zones start out as representing 1 gene (can be overlapping)
    //Since they can represent a collection of genes,
    //They are chopped during the intersection process and overlap regions become new zones
    const Elysia::Genome::Chromosome *fatherMother[2];
    fatherMother[0]=&genes.fathers();
    fatherMother[1]=&genes.mothers();
    //Loop through all the genes
    for (int chromosomeNum=0;chromosomeNum<2;++chromosomeNum) {
       int num_genes=fatherMother[chromosomeNum]->genes_size();
       for (int i=0;i<num_genes;++i) {
          //Define the new zone
          const Elysia::Genome::Gene*gene=&fatherMother[chromosomeNum]->genes(i);
          int num_bounds=gene->bounds_size();
          for (int k=0;k<num_bounds;++k) {
              ProteinZone newZone;
              newZone.mGenes.push_back(*gene);
              int num_proteins=gene->external_proteins_size();
              for (int j=0;j<num_proteins;++j) {
                  const Elysia::Genome::Protein *protein=&gene->external_proteins(j);
                  newZone.mSoup.push_back(ProteinZone::EffectAndDensityPair(protein->protein_code(),protein->density()));
              }
              newZone.mBounds =BoundingBox3f3f(Vector3f(gene->bounds(k).minx(),
                                                        gene->bounds(k).miny(),
                                                        gene->bounds(k).minz()),
                                               Vector3f(gene->bounds(k).maxx(),
                                                        gene->bounds(k).maxy(),
                                                        gene->bounds(k).maxz()));
              mMainZoneList.push_back(newZone);
          }
       }
    }
	zoneIntersection(mMainZoneList);
    return *this;
}

//Find the "specific protein density" total up the protein (given effect)
//Return the magnitude of a given effect.
float SimpleProteinEnvironment::ProteinZone::getSpecificProteinDensity(Elysia::Genome::Effect e){
  float retval=0;
  std::vector< std::pair<Elysia::Genome::Effect,float> >::const_iterator i,ie;
  for (i=mSoup.begin(),ie=mSoup.end();i!=ie;++i) {
  //if the effect in the current iterator matches the desired protein effect passed in as "e", add the float to the return value
        if (i->first==e) retval+=i->second;
  }
  return retval;
}

//Get protein density at a location (given location, and protein effect interested in)
//Return float of the effect's density
float SimpleProteinEnvironment::getProteinDensity(const Vector3f &location, const Elysia::Genome::Effect&effect) {
  float density=0;
  ///loop through all protein zones
  for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
    //if our test point is in the zone
    if (i->getBoundingBox().contains(location)) {
        //then accumulate the matching effect (if present) into final result
        density+=i->getSpecificProteinDensity(effect);
    }
  }
  //and return the result
  return density;
}

//Find all the proteins at a given point (given location)
//Return vector of proteins
std::vector<std::pair<Elysia::Genome::Effect, float> > SimpleProteinEnvironment::getCompleteProteinDensity(const Vector3f& location){
  std::vector<ProteinZone::EffectAndDensityPair >proteins;
  //loop through all the zones
  for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
    //if our test point is in the zone
    if (i->getBoundingBox().contains(location)) {
        //Append the effects (i.e. mSoup) to the end of the returned proteins
        proteins.insert(proteins.end(),i->mSoup.begin(),i->mSoup.end());
    }
  }
  return proteins;
}

//Update ALL the mSoup (densities) for the next timestep, (given the current age)
//Return nothing
// These functions are not ready yet--- we should get LNK errors for them so we know when we're done
//"Complicated" function to update the soup for the next time iteration
void SimpleProteinEnvironment::ProteinZone::updateSoupToNextSoup(const float age){
	//Will write this function last
}

//The area is not equal in any aspect -> not OK
static bool okArea(const BoundingBox3f3f&input) {
  return input.min().x!=input.max().x&&input.min().y!=input.max().y;
}

template <class T> BoundingBox<T> intersect(const BoundingBox<T>&a, const BoundingBox<T>&b) {
   BoundingBox<T> retval(a.min().max(b.min()),a.max().min(b.max()));
   if (retval.diag().x<=0||retval.diag().y<=0) {
      return BoundingBox<T>(retval.min(),retval.min());//null bounding box at min
   }
   return retval;
}

//Combine genes into a single-shared region
 SimpleProteinEnvironment::ProteinZone SimpleProteinEnvironment::combineZone(const SimpleProteinEnvironment::ProteinZone &a, const SimpleProteinEnvironment::ProteinZone&b , const BoundingBox3f3f &bbox) {
   ProteinZone retval;
   retval.mBounds=bbox;
   assert(!a.mSoup.empty()&&!b.mSoup.empty());
   //Combine the genes into a shared, common sized, region
   retval.mGenes.insert(retval.mGenes.end(),a.mGenes.begin(),a.mGenes.end());
   retval.mGenes.insert(retval.mGenes.end(),b.mGenes.begin(),b.mGenes.end());
   return retval;
}

//Relocate a zone to a new box location
SimpleProteinEnvironment::ProteinZone SimpleProteinEnvironment::relocateZone(ProteinZone a, const BoundingBox3f3f &bbox) { //generate a box of type a
   a.mBounds=bbox;
   return a;
}

//Merge 2 zones of same gene type
void SimpleProteinEnvironment::combineZonesFromSameGene(ProteinZone &a, const ProteinZone&b) {
   a.mBounds.mergeIn(b.mBounds);
}

//Combine 2 zones by dividing it up into parts before reassembling them
void SimpleProteinEnvironment::chopZonePair(const ProteinZone &a, const ProteinZone &b, std::vector<ProteinZone> &output) {
    // Assume any combination of 2 zones will results in 9 subsections
    // Figure out using the intersections points how to generate the subsections
    // Subsections of area 0 --> ignore
    // Add subsections of significant areas to the list with the proper gene type
    // Combine subsections of similar gene type horizontally
  ProteinZone ab[2]={a,b};  //combine a and b into a list
  if (!okArea(intersect(ab[0].mBounds,ab[1].mBounds))) {
     output.push_back(a);
     output.push_back(b);
     return;
  }
  float horizedges[4]={ab[0].mBounds.min().x,ab[1].mBounds.min().x,ab[0].mBounds.max().x,ab[1].mBounds.max().x};  //generate list of x bounds
  float vertedges[4]={ab[0].mBounds.min().y,ab[1].mBounds.min().y,ab[0].mBounds.max().y,ab[1].mBounds.max().y};  //generate lsit of y bounds
  std::sort(horizedges+0,horizedges+4);  //Sort the horizontal list left->right (min->max)
  std::sort(vertedges+0,vertedges+4);  //Sort the vertical list top->bottom (min->max)
  bool combinable[3][3][2];
  ProteinZone combiners[3][3][2];
  //Loop through the subsections
  for (int i=0;i<3;++i) {
    for (int j=0;j<3;++j) {
      BoundingBox3f3f newBounds[2];
      //Generate one section 1->9 (corner-to-corner)
      BoundingBox3f3f location(Vector3f(horizedges[i],vertedges[j],a.mBounds.min().z),
                                   Vector3f(horizedges[i+1],vertedges[j+1],a.mBounds.max().z));
      bool valid[2];
      for (int z=0;z<2;++z) {
         //Is it inside a or b?
         valid[z]=okArea(newBounds[z]=intersect(location,ab[z].mBounds));
         combinable[i][j][z]=false;
      }
      if (valid[0]&&valid[1]) { //It is a subsection of A and B
         output.push_back(combineZone(a,b,location));
      } else if (valid[0]) { //It is a subsection of A
         combiners[i][j][0]=relocateZone(ab[0],newBounds[0]);
         combinable[i][j][0]=true;
      } else if (valid[1]) { //It is a subsection of B
         combiners[i][j][0]=relocateZone(ab[1],newBounds[1]);
         combinable[i][j][1]=true;
      }
    }
  }
  //Results in 9 subsections of type A, B and AB

  //Loop through the subsections and determine zones that are neighbors (horizontal)
  for (int z=0;z<2;++z) {
    for (int i=0;i<3;++i) {
      for (int j=0;j<2;++j) {
         if (combinable[i][j][z]&&combinable[i][j+1][z]) {
            combineZonesFromSameGene(combiners[i][j+1][z],combiners[i][j][z]);
            combinable[i][j][z]=false;
         }
       }
    }
  }
  //send back combined zones
  for (int z=0;z<2;++z) {
    for (int i=0;i<3;++i) {
      for (int j=0;j<3;++j) {
         if (combinable[i][j][z]) {
            output.push_back(combiners[i][j][z]);
         }
      }
    }
  }
}

//Split and simplify large zone definitions into smaller component zones for calculations (given list of all zones)
//Return a list of zones (post-split)
void SimpleProteinEnvironment::zoneIntersection(std::vector<ProteinZone> mMainZoneList){
	std::vector<ProteinZone> mLocalZoneList;
	std::vector<ProteinZone> mSwapZoneList;
	mLocalZoneList = mMainZoneList;
	mSwapZoneList = mMainZoneList;
	bool converged=false;
	bool restart=false;

	while (!converged) {
		//Defaults to converged incase for-loop and detection never terminates
    	converged=true;

    	//Loop through zones and check intersection (for row from start-->end)
    	for (std::vector<ProteinZone>::iterator i=mMainZoneList.begin(),ie=mMainZoneList.end();i!=ie;++i) {
			//(for column from current-row-diagonal + 1 --> end) ==> results in half triangle w/o diagonal
	    	for (std::vector<ProteinZone>::iterator j=i+1,je=mMainZoneList.end();j!=je;++j) {
				if(!restart){
					mLocalZoneList.clear();	//ensure that the list returned is initialized properly
					mSwapZoneList.clear();		//ensure that the list returned is initialized properly
					chopZonePair(*i,*j,mLocalZoneList);
					if(mLocalZoneList.size() == 2){
						if( ((i->mBounds == mLocalZoneList[0].mBounds)  ||
							 (i->mBounds == mLocalZoneList[1].mBounds)) ||
							((j->mBounds == mLocalZoneList[0].mBounds)  ||
							 (j->mBounds == mLocalZoneList[1].mBounds)) ){
							//Technicaly, I only need to look at only i, or j, but the 2nd set it a sanity check
							//No new zones were created
							//-No action
						}else{
							//These are 2 new zones
							//-Create new zones excluding current 2
							//-Append new zones to list
							//-Restart -> Swap
							rebuildZones(i,j,mMainZoneList,mSwapZoneList);
							addZones(mLocalZoneList,mSwapZoneList);
							restart = true;
						}
					}else if ((mLocalZoneList.size() > 2)||(mLocalZoneList.size() == 1)){
						//These are all new zones
						//-Create new zones excluding current 2
						//-Append new zones to list
						//-Restart -> Swap
						rebuildZones(i,j,mMainZoneList,mSwapZoneList);
						addZones(mLocalZoneList,mSwapZoneList);
						restart = true;
					}else{
						//Serious error... should not be 0 or fewer
					}
				}//end if
    		}//end for
    	}//end for

		if(restart){
			mMainZoneList.swap(mSwapZoneList);
			converged=false;
			restart=false;
		}

	}//end while
}

//Rebuild the zone list such that it exclude the 2 zones currently in question
//This allows us to throw out the 2 zones and add their replacements
void SimpleProteinEnvironment::rebuildZones(std::vector<ProteinZone>::const_iterator a,std::vector<ProteinZone>::const_iterator b, const std::vector<ProteinZone> &input, std::vector<ProteinZone> &output) {
    // Create a new list excluding the current 2 zones
	for (std::vector<ProteinZone>::const_iterator i=input.begin(),ie=input.end();i!=ie;++i) {
		if( (i != a)&&(i != b) ){
			output.push_back(*i);
		}
	}
	return;
}

//Zone management functions to add zones to the main list (given sub-list, and main-list)
//Return new main-list
void SimpleProteinEnvironment::addZones( const std::vector<ProteinZone> &mSubZoneList,
                                        std::vector<ProteinZone> &mMainZoneList){
    //Append all the zones in the sub-list to the main-list
	for (std::vector<ProteinZone>::const_iterator i=mSubZoneList.begin(),ie=mSubZoneList.end();i!=ie;++i) {
		mMainZoneList.push_back(*i);
	}
	return;
}

//Zone management functions to remove zones from the main list (given sub-list, and main-list)
//Return new main-list
void SimpleProteinEnvironment::removeZones(  std::vector<ProteinZone> mSubZoneList,
                                            std::vector<ProteinZone> mMainZoneList){
    //Find and remove all matching entries in the sub-list out of the main-list
}

//Function to find the zone that a single point reside in (given point, and zone list)
//Return THE zone from the list that is inside the point, or fail
SimpleProteinEnvironment::ProteinZone &SimpleProteinEnvironment::resideInZones(   const Vector3f queryPoint,
                                                        std::vector<ProteinZone> mMainZoneList){
	int i;
	static ProteinZone myFail;
	size_t numMainZones=mMainZoneList.size();

	for(size_t i=0;i<mMainZoneList.size();++i){
		if (mMainZoneList[i].mBounds.contains(queryPoint)) {
			return mMainZoneList[i];
		}
	}

	return myFail;
}

const Elysia::Genome::Gene& SimpleProteinEnvironment::retrieveGene(const Vector3f &location, const Elysia::Genome::Effect&effect){
  assert(0);
  //FIXME actually look up the responsible gene from the set of "active" genes causing the effect to be spilled at this location
  static Elysia::Genome::Gene retval;
  return retval;
}

SimpleProteinEnvironment::~SimpleProteinEnvironment(){
}

}
<|endoftext|>