<commit_before>#include <functional>

#include "arch/runtime/starter.hpp"
#include "serializer/config.hpp"
#include "unittest/mock_file.hpp"
#include "unittest/gtest.hpp"

namespace unittest {

// This test is completely vacuous, but should invite expansion in the future.

void run_CreateConstructDestroy() {
    // This serves more as a mock_file_t test than a serializer test.
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());
}

TEST(SerializerTest, CreateConstructDestroy) {
    run_in_thread_pool(run_CreateConstructDestroy, 4);
}

void run_AddDeleteRepeatedly(bool perform_index_write) {
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());

    scoped_malloc_t<ser_buffer_t> buf = ser.malloc();
    memset(buf->cache_data, 0, ser.get_block_size().value());

    scoped_ptr_t<file_account_t> account(ser.make_io_account(1));

    debugf("doing operation 0-19999\n");
    for (int i = 0; i < 200000; ++i) {
        const block_id_t block_id = i;
        std::vector<buf_write_info_t> infos;
        infos.push_back(buf_write_info_t(buf.get(), ser.get_block_size(), block_id));

        // Create the block
        struct : public iocallback_t, public cond_t {
            void on_io_complete() {
                pulse();
            }
        } cb;

        std::vector<counted_t<standard_block_token_t> > tokens
            = ser.block_writes(infos, account.get(), &cb);

        // Wait for it to be written (because we're nice).
        cb.wait();

        if (perform_index_write) {
            // Do an index write creating the block.
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, tokens[0], repli_timestamp_t::distant_past));
                ser.index_write(write_ops, account.get());
            }
            // Now delete the only block token and delete the index reference.
            tokens.clear();
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, counted_t<standard_block_token_t>()));
                ser.index_write(write_ops, account.get());
            }

        } else {
            // Now delete the only block token.
            tokens.clear();
        }
    }
}

TEST(SerializerTest, AddDeleteRepeatedly) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, false), 4);
}

TEST(SerializerTest, AddDeleteRepeatedlyWithIndex) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, true), 4);
}

}  // namespace unittest
<commit_msg>Removed a debugf in run_AddDeleteRepeatedly.<commit_after>#include <functional>

#include "arch/runtime/starter.hpp"
#include "serializer/config.hpp"
#include "unittest/mock_file.hpp"
#include "unittest/gtest.hpp"

namespace unittest {

// This test is completely vacuous, but should invite expansion in the future.

void run_CreateConstructDestroy() {
    // This serves more as a mock_file_t test than a serializer test.
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());
}

TEST(SerializerTest, CreateConstructDestroy) {
    run_in_thread_pool(run_CreateConstructDestroy, 4);
}

void run_AddDeleteRepeatedly(bool perform_index_write) {
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());

    scoped_malloc_t<ser_buffer_t> buf = ser.malloc();
    memset(buf->cache_data, 0, ser.get_block_size().value());

    scoped_ptr_t<file_account_t> account(ser.make_io_account(1));

    for (int i = 0; i < 200000; ++i) {
        const block_id_t block_id = i;
        std::vector<buf_write_info_t> infos;
        infos.push_back(buf_write_info_t(buf.get(), ser.get_block_size(), block_id));

        // Create the block
        struct : public iocallback_t, public cond_t {
            void on_io_complete() {
                pulse();
            }
        } cb;

        std::vector<counted_t<standard_block_token_t> > tokens
            = ser.block_writes(infos, account.get(), &cb);

        // Wait for it to be written (because we're nice).
        cb.wait();

        if (perform_index_write) {
            // Do an index write creating the block.
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, tokens[0], repli_timestamp_t::distant_past));
                ser.index_write(write_ops, account.get());
            }
            // Now delete the only block token and delete the index reference.
            tokens.clear();
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, counted_t<standard_block_token_t>()));
                ser.index_write(write_ops, account.get());
            }

        } else {
            // Now delete the only block token.
            tokens.clear();
        }
    }
}

TEST(SerializerTest, AddDeleteRepeatedly) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, false), 4);
}

TEST(SerializerTest, AddDeleteRepeatedlyWithIndex) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, true), 4);
}

}  // namespace unittest
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/targeting/common/util.C $                             */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2015                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file targeting/common/util.C
 *
 *  @brief Provides miscellaneous utility functions to targeting, including
 *     a check for whether system is in simulation or not.
 */

//******************************************************************************
// Includes
//******************************************************************************
#include <stdint.h>
#include <targeting/common/attributes.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/utilFilter.H>

namespace TARGETING
{

/**
 * @brief Checks to see if we are running in a hardware simulation
 *    environment, i.e. VPO/VBU  (not Simics)
 */
bool is_vpo( void )
{
    struct IsVpoFunctor
    {
        static bool operate()
        {
            bool rc = false;

            Target* sys = NULL;
            targetService().getTopLevelTarget(sys);

            uint8_t vpo_mode = 0;
            if (unlikely(sys &&
                         sys->tryGetAttr<ATTR_IS_SIMULATION>(vpo_mode) &&
                         (1 == vpo_mode)))
            {
                rc = true;
            }
            return rc;
        }
    };

#ifdef __HOSTBOOT_MODULE
    // In Hostboot this value cannot change, so cache it as a static.
    static bool is_vpo_mode = IsVpoFunctor::operate();
    return is_vpo_mode;
#else
    // On FSP, assumption is that the user could change this, so we cannot
    // cache it as a static.  Read from the attribute directly.
    return IsVpoFunctor::operate();
#endif
};

/**
 * @brief Safely fetch the HUID of a Target
 */
uint32_t get_huid( const Target* i_target )
{
    uint32_t huid = 0;
    if( i_target == NULL )
    {
        huid = 0x0;
    }
    else if( i_target == MASTER_PROCESSOR_CHIP_TARGET_SENTINEL )
    {
        huid = 0xFFFFFFFF;
    }
    else
    {
        i_target->tryGetAttr<ATTR_HUID>(huid);
    }
    return huid;
}

/**
 * @brief set HWAS Changed flag to subscription mask
 *
 *   This will be used by the HCDB service - when the target has
 *   changed, this will get called to tell the appropriate services
 *   that the change has occurred.
 */
void update_hwas_changed_mask(Target * i_target)
{
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(
            i_target->getAttr<ATTR_HWAS_STATE_CHANGED_SUBSCRIPTION_MASK>());
}

/**
 * @brief set HWAS Changed flag to specific bits
 *
 *   This will be used by different services when the target needs processing.
 */
void update_hwas_changed_mask(Target * i_target, const uint64_t i_bits)
{
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(
            i_target->getAttr<ATTR_HWAS_STATE_CHANGED_FLAG>() |
            (i_target->getAttr<ATTR_HWAS_STATE_CHANGED_SUBSCRIPTION_MASK>() &
                i_bits));
}

/**
 * @brief clear bit in HWAS Changed Mask
 *
 *   This will be used by the appropriate services when they have handled
 *   the change flag for this target.
 */
void clear_hwas_changed_bit(Target * i_target, const HWAS_CHANGED_BIT i_bit)
{
    ATTR_HWAS_STATE_CHANGED_FLAG_type hwasChangedState =
        i_target->getAttr<ATTR_HWAS_STATE_CHANGED_FLAG>();
    hwasChangedState &= ~i_bit;
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(hwasChangedState);
}

/**
 * @brief   Checks if we are loading a PHYP payload
 */
bool is_phyp_load( ATTR_PAYLOAD_KIND_type* o_type )
{
    Target* sys = NULL;
    targetService().getTopLevelTarget( sys );
    assert(sys != NULL);

    // get the current payload kind
    TARGETING::PAYLOAD_KIND payload_kind = sys->getAttr<ATTR_PAYLOAD_KIND>();

    if( o_type )
    {
        *o_type = payload_kind;
    }

    //If in AVP mode default to false
    bool is_phyp = false;
    if(!is_avp_load())
    {
        is_phyp = (PAYLOAD_KIND_PHYP == payload_kind);
    }
    return is_phyp;
 }

/**
 * @brief  Utility function to determine if Sapphire is the payload
 *
 * @description  If the payload kind is Sapphire returns true.  Does
 *    not matter if it is Sapphire with FSP or standalone
 *
 * @return bool  True when loadding sapphire
 */
bool is_sapphire_load(void)
{
    TARGETING::Target * sys = NULL;
    TARGETING::targetService().getTopLevelTarget( sys );
    assert(sys != NULL);
    bool is_sapphire = false;

    //If in AVP mode default to false
    if(!is_avp_load())
    {
        is_sapphire = (PAYLOAD_KIND_SAPPHIRE ==
                       sys->getAttr<TARGETING::ATTR_PAYLOAD_KIND>());
    }
    return is_sapphire;
}

/**
 * @brief  Utility function to determine if an AVP is the payload
 *         Note the actual payload could be something else -- this
 *         is based solely on MFG flags
 *
 * @description  If MFG AVP mode flags are set then returns true
 *      Does not matter what the actual payload is
 *
 * @return bool  True when in AVP mode
 */
bool is_avp_load(void)
{
    TARGETING::Target * sys = NULL;
    TARGETING::targetService().getTopLevelTarget( sys );
    assert(sys != NULL);

    TARGETING::ATTR_MNFG_FLAGS_type mnfg_flags =
      sys->getAttr<TARGETING::ATTR_MNFG_FLAGS>();
    return ((mnfg_flags & TARGETING::MNFG_FLAG_AVP_ENABLE)
       || (mnfg_flags & TARGETING::MNFG_FLAG_HDAT_AVP_ENABLE));
}

/**
 * @brief Utility function to obtain the highest known address in the system
 */
uint64_t get_top_mem_addr(void)
{
    uint64_t top_addr = 0;

    do
    {
        // Get all functional proc chip targets
        TARGETING::TargetHandleList l_cpuTargetList;
        TARGETING::getAllChips(l_cpuTargetList, TYPE_PROC);

        for ( size_t proc = 0; proc < l_cpuTargetList.size(); proc++ )
        {
            TARGETING::Target * l_pProc = l_cpuTargetList[proc];

            //Not checking success here as fail results in no change to
            // top_addr
            uint64_t l_mem_bases[8] = {0,};
            uint64_t l_mem_sizes[8] = {0,};
            l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_mem_bases);
            l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES>(l_mem_sizes);

            for (size_t i=0; i< 8; i++)
            {
                if(l_mem_sizes[i]) //non zero means that there is memory present
                {
                    top_addr = std::max(top_addr,
                                        l_mem_bases[i] + l_mem_sizes[i]);
                }
            }
        }
    }while(0);

    return top_addr;
}

/**
 * @brief Utility function to obtain the lowest known address in the system
 */
uint64_t get_bottom_mem_addr(void)
{
    uint64_t bottom_addr = UINT64_MAX;

    do
    {
        // Get all functional proc chip targets
        TARGETING::TargetHandleList l_cpuTargetList;
        TARGETING::getAllChips(l_cpuTargetList, TYPE_PROC);

        for ( size_t proc = 0; proc < l_cpuTargetList.size(); proc++ )
        {
            TARGETING::Target * l_pProc = l_cpuTargetList[proc];

            uint64_t l_mem_bases[8] = {};
            uint64_t l_mem_sizes[8] = {};
            TARG_ASSERT(
               l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_mem_bases),
               "Unable to get ATTR_PROC_MEM_BASES attribute");

            TARG_ASSERT(
               l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES>(l_mem_sizes),
               "Unable to get ATTR_PROC_MEM_SIZES attribute");

            for (size_t i=0; i< 8; i++)
            {
                if(l_mem_sizes[i]) //non zero means that there is memory present
                {
                    bottom_addr = std::min(bottom_addr, l_mem_bases[i]);
                }
            }
        }
    }while(0);

    // There's no reason the lowest address should be the largest
    // 64 bit value
    TARG_ASSERT(
        bottom_addr < UINT64_MAX,
        "Lowest address is maximum 64-bit value");

    return bottom_addr;
}

bool orderByNodeAndPosition(  Target* i_firstProc,
                              Target* i_secondProc)
{
    uint8_t nodeId0 = i_firstProc->getAttr<ATTR_FABRIC_NODE_ID>();
    uint8_t nodeId1 = i_secondProc->getAttr<ATTR_FABRIC_NODE_ID>();
    uint8_t fabpos0 = i_firstProc->getAttr<ATTR_FABRIC_CHIP_ID>();
    uint8_t fabpos1 = i_secondProc->getAttr<ATTR_FABRIC_CHIP_ID>();

    if (nodeId0 == nodeId1)
    {
        return fabpos0 < fabpos1;
    }
    return nodeId0 < nodeId1;
}

}
<commit_msg>Improve error message for no memory situation<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/targeting/common/util.C $                             */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2015                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file targeting/common/util.C
 *
 *  @brief Provides miscellaneous utility functions to targeting, including
 *     a check for whether system is in simulation or not.
 */

//******************************************************************************
// Includes
//******************************************************************************
#include <stdint.h>
#include <targeting/common/attributes.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/utilFilter.H>

namespace TARGETING
{

/**
 * @brief Checks to see if we are running in a hardware simulation
 *    environment, i.e. VPO/VBU  (not Simics)
 */
bool is_vpo( void )
{
    struct IsVpoFunctor
    {
        static bool operate()
        {
            bool rc = false;

            Target* sys = NULL;
            targetService().getTopLevelTarget(sys);

            uint8_t vpo_mode = 0;
            if (unlikely(sys &&
                         sys->tryGetAttr<ATTR_IS_SIMULATION>(vpo_mode) &&
                         (1 == vpo_mode)))
            {
                rc = true;
            }
            return rc;
        }
    };

#ifdef __HOSTBOOT_MODULE
    // In Hostboot this value cannot change, so cache it as a static.
    static bool is_vpo_mode = IsVpoFunctor::operate();
    return is_vpo_mode;
#else
    // On FSP, assumption is that the user could change this, so we cannot
    // cache it as a static.  Read from the attribute directly.
    return IsVpoFunctor::operate();
#endif
};

/**
 * @brief Safely fetch the HUID of a Target
 */
uint32_t get_huid( const Target* i_target )
{
    uint32_t huid = 0;
    if( i_target == NULL )
    {
        huid = 0x0;
    }
    else if( i_target == MASTER_PROCESSOR_CHIP_TARGET_SENTINEL )
    {
        huid = 0xFFFFFFFF;
    }
    else
    {
        i_target->tryGetAttr<ATTR_HUID>(huid);
    }
    return huid;
}

/**
 * @brief set HWAS Changed flag to subscription mask
 *
 *   This will be used by the HCDB service - when the target has
 *   changed, this will get called to tell the appropriate services
 *   that the change has occurred.
 */
void update_hwas_changed_mask(Target * i_target)
{
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(
            i_target->getAttr<ATTR_HWAS_STATE_CHANGED_SUBSCRIPTION_MASK>());
}

/**
 * @brief set HWAS Changed flag to specific bits
 *
 *   This will be used by different services when the target needs processing.
 */
void update_hwas_changed_mask(Target * i_target, const uint64_t i_bits)
{
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(
            i_target->getAttr<ATTR_HWAS_STATE_CHANGED_FLAG>() |
            (i_target->getAttr<ATTR_HWAS_STATE_CHANGED_SUBSCRIPTION_MASK>() &
                i_bits));
}

/**
 * @brief clear bit in HWAS Changed Mask
 *
 *   This will be used by the appropriate services when they have handled
 *   the change flag for this target.
 */
void clear_hwas_changed_bit(Target * i_target, const HWAS_CHANGED_BIT i_bit)
{
    ATTR_HWAS_STATE_CHANGED_FLAG_type hwasChangedState =
        i_target->getAttr<ATTR_HWAS_STATE_CHANGED_FLAG>();
    hwasChangedState &= ~i_bit;
    i_target->setAttr<ATTR_HWAS_STATE_CHANGED_FLAG>(hwasChangedState);
}

/**
 * @brief   Checks if we are loading a PHYP payload
 */
bool is_phyp_load( ATTR_PAYLOAD_KIND_type* o_type )
{
    Target* sys = NULL;
    targetService().getTopLevelTarget( sys );
    assert(sys != NULL);

    // get the current payload kind
    TARGETING::PAYLOAD_KIND payload_kind = sys->getAttr<ATTR_PAYLOAD_KIND>();

    if( o_type )
    {
        *o_type = payload_kind;
    }

    //If in AVP mode default to false
    bool is_phyp = false;
    if(!is_avp_load())
    {
        is_phyp = (PAYLOAD_KIND_PHYP == payload_kind);
    }
    return is_phyp;
 }

/**
 * @brief  Utility function to determine if Sapphire is the payload
 *
 * @description  If the payload kind is Sapphire returns true.  Does
 *    not matter if it is Sapphire with FSP or standalone
 *
 * @return bool  True when loadding sapphire
 */
bool is_sapphire_load(void)
{
    TARGETING::Target * sys = NULL;
    TARGETING::targetService().getTopLevelTarget( sys );
    assert(sys != NULL);
    bool is_sapphire = false;

    //If in AVP mode default to false
    if(!is_avp_load())
    {
        is_sapphire = (PAYLOAD_KIND_SAPPHIRE ==
                       sys->getAttr<TARGETING::ATTR_PAYLOAD_KIND>());
    }
    return is_sapphire;
}

/**
 * @brief  Utility function to determine if an AVP is the payload
 *         Note the actual payload could be something else -- this
 *         is based solely on MFG flags
 *
 * @description  If MFG AVP mode flags are set then returns true
 *      Does not matter what the actual payload is
 *
 * @return bool  True when in AVP mode
 */
bool is_avp_load(void)
{
    TARGETING::Target * sys = NULL;
    TARGETING::targetService().getTopLevelTarget( sys );
    assert(sys != NULL);

    TARGETING::ATTR_MNFG_FLAGS_type mnfg_flags =
      sys->getAttr<TARGETING::ATTR_MNFG_FLAGS>();
    return ((mnfg_flags & TARGETING::MNFG_FLAG_AVP_ENABLE)
       || (mnfg_flags & TARGETING::MNFG_FLAG_HDAT_AVP_ENABLE));
}

/**
 * @brief Utility function to obtain the highest known address in the system
 */
uint64_t get_top_mem_addr(void)
{
    uint64_t top_addr = 0;

    do
    {
        // Get all functional proc chip targets
        TARGETING::TargetHandleList l_cpuTargetList;
        TARGETING::getAllChips(l_cpuTargetList, TYPE_PROC);

        for ( size_t proc = 0; proc < l_cpuTargetList.size(); proc++ )
        {
            TARGETING::Target * l_pProc = l_cpuTargetList[proc];

            //Not checking success here as fail results in no change to
            // top_addr
            uint64_t l_mem_bases[8] = {0,};
            uint64_t l_mem_sizes[8] = {0,};
            l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_mem_bases);
            l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES>(l_mem_sizes);

            for (size_t i=0; i< 8; i++)
            {
                if(l_mem_sizes[i]) //non zero means that there is memory present
                {
                    top_addr = std::max(top_addr,
                                        l_mem_bases[i] + l_mem_sizes[i]);
                }
            }
        }
    }while(0);

    return top_addr;
}

/**
 * @brief Utility function to obtain the lowest known address in the system
 */
uint64_t get_bottom_mem_addr(void)
{
    uint64_t bottom_addr = UINT64_MAX;

    do
    {
        // Get all functional proc chip targets
        TARGETING::TargetHandleList l_cpuTargetList;
        TARGETING::getAllChips(l_cpuTargetList, TYPE_PROC);

        for ( size_t proc = 0; proc < l_cpuTargetList.size(); proc++ )
        {
            TARGETING::Target * l_pProc = l_cpuTargetList[proc];

            uint64_t l_mem_bases[8] = {};
            uint64_t l_mem_sizes[8] = {};
            TARG_ASSERT(
               l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_mem_bases),
               "Unable to get ATTR_PROC_MEM_BASES attribute");

            TARG_ASSERT(
               l_pProc->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES>(l_mem_sizes),
               "Unable to get ATTR_PROC_MEM_SIZES attribute");

            for (size_t i=0; i< 8; i++)
            {
                if(l_mem_sizes[i]) //non zero means that there is memory present
                {
                    bottom_addr = std::min(bottom_addr, l_mem_bases[i]);
                }
            }
        }
    }while(0);

    // There's no reason the lowest address should be the largest
    // 64 bit value
    TARG_ASSERT(
        bottom_addr < UINT64_MAX,
        "Lowest address is maximum 64-bit value, probably have no memory");

    return bottom_addr;
}

bool orderByNodeAndPosition(  Target* i_firstProc,
                              Target* i_secondProc)
{
    uint8_t nodeId0 = i_firstProc->getAttr<ATTR_FABRIC_NODE_ID>();
    uint8_t nodeId1 = i_secondProc->getAttr<ATTR_FABRIC_NODE_ID>();
    uint8_t fabpos0 = i_firstProc->getAttr<ATTR_FABRIC_CHIP_ID>();
    uint8_t fabpos1 = i_secondProc->getAttr<ATTR_FABRIC_CHIP_ID>();

    if (nodeId0 == nodeId1)
    {
        return fabpos0 < fabpos1;
    }
    return nodeId0 < nodeId1;
}

}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSetRegionTool.h"

#include "mitkToolManager.h"
#include "mitkOverwriteSliceImageFilter.h"

#include "ipSegmentation.h"

#include "mitkBaseRenderer.h"

mitk::SetRegionTool::SetRegionTool(int paintingPixelValue)
:SegTool2D("PressMoveReleaseWithCTRLInversion"),
 m_PaintingPixelValue(paintingPixelValue),
 m_FillContour(false),
 m_StatusFillWholeSlice(false)
{
}

mitk::SetRegionTool::~SetRegionTool()
{
}

void mitk::SetRegionTool::Activated()
{
  Superclass::Activated();
}

void mitk::SetRegionTool::Deactivated()
{
  Superclass::Deactivated();
}

bool mitk::SetRegionTool::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  if (!SegTool2D::OnMousePressed( action, stateEvent )) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  // 1. Get the working image
  Image::Pointer workingSlice   = SegTool2D::GetAffectedWorkingSlice( positionEvent );
  if ( workingSlice.IsNull() ) return false; // can't do anything without the segmentation

  // if click was outside the image, don't continue
  const Geometry3D* sliceGeometry = workingSlice->GetGeometry();
  itk::Index<2> projectedPointIn2D;
  sliceGeometry->WorldToIndex( positionEvent->GetWorldPosition(), projectedPointIn2D );
  if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) )
  {
    std::cout << "point apparently not inside segmentation slice" << std::endl;
    return false; // can't use that as a seed point
  }

    // Convert to ipMITKSegmentationTYPE (because ipMITKSegmentationGetContour8N relys on that data type)
    itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage;
    CastToItkImage( workingSlice, correctPixelTypeImage );
    assert (correctPixelTypeImage.IsNotNull() );

  // possible bug in CastToItkImage ?
  // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in
  // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479:
  // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed
  // solution here: we overwrite it with an unity matrix
  itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection;
  imageDirection.SetIdentity();
  correctPixelTypeImage->SetDirection(imageDirection);

    Image::Pointer temporarySlice = Image::New();
  //  temporarySlice = ImportItkImage( correctPixelTypeImage );
    CastToMitkImage( correctPixelTypeImage, temporarySlice );

  // check index positions
  ipPicDescriptor* originalPicSlice = temporarySlice->GetSliceData()->GetPicDescriptor();

  int m_SeedPointMemoryOffset = projectedPointIn2D[1] * originalPicSlice->n[0] + projectedPointIn2D[0];

  if ( m_SeedPointMemoryOffset >= static_cast<int>( originalPicSlice->n[0] * originalPicSlice->n[1] ) ||
       m_SeedPointMemoryOffset < 0 )
  {
    std::cerr << "Memory offset calculation if mitk::SetRegionTool has some serious flaw! Aborting.." << std::endl;
    return false;
  }

  // 2. Determine the contour that surronds the selected "piece of the image"

  // find a contour seed point
  unsigned int oneContourOffset = static_cast<unsigned int>( m_SeedPointMemoryOffset ); // safe because of earlier check if m_SeedPointMemoryOffset < 0

  /**
    * The logic of finding a starting point for the contour is the following:
    *
    *  - If the initial seed point is 0, we are either inside a hole or outside of every segmentation.
    *    We move to the right until we hit a 1, which must be part of a contour.
    *
    *  - If the initial seed point is 1, then ...
    *    we now do the same (running to the right) until we hit a 1
    *
    *  In both cases the found contour point is used to extract a contour and
    *  then a test is applied to find out if the initial seed point is contained
    *  in the contour. If this is the case, filling should be applied, otherwise
    *  nothing is done.
    */
  unsigned int size = originalPicSlice->n[0] * originalPicSlice->n[1];
/*
  unsigned int rowSize = originalPicSlice->n[0];
*/
  ipMITKSegmentationTYPE* data = static_cast<ipMITKSegmentationTYPE*>(originalPicSlice->data);

  if ( data[oneContourOffset] == 0 ) // initial seed 0
  {
    for ( ; oneContourOffset < size; ++oneContourOffset )
    {
      if ( data[oneContourOffset] > 0 ) break;
    }
  }
  else if ( data[oneContourOffset] == 1 ) // initial seed 1
  {
    unsigned int lastValidPixel = size-1; // initialization, will be changed lateron
    bool inSeg = true;    // inside segmentation?
    for ( ; oneContourOffset < size; ++oneContourOffset )
    {
      if ( ( data[oneContourOffset] == 0 ) && inSeg ) // pixel 0 and inside-flag set: this happens at the first pixel outside a filled region
      {
        inSeg = false;
        lastValidPixel = oneContourOffset - 1; // store the last pixel position inside a filled region
        break;
      }
      else // pixel 1, inside-flag doesn't matter: this happens while we are inside a filled region
      {
        inSeg = true; // first iteration lands here
      }

    }
    oneContourOffset = lastValidPixel;
  }
  else
  {
    std::cerr << "Fill/Erase was never intended to work with other than binary images." << std::endl;
    m_FillContour = false;
    return false;
  }

  if (oneContourOffset == size) // nothing found until end of slice
  {
    m_FillContour = false;
    return false;
  }

  int numberOfContourPoints( 0 );
  int newBufferSize( 0 );
  float* contourPoints = ipMITKSegmentationGetContour8N( originalPicSlice, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc

  bool cursorInsideContour = ipMITKSegmentationIsInsideContour( contourPoints, numberOfContourPoints, projectedPointIn2D[0], projectedPointIn2D[1]);

  // decide if contour should be filled or not
  m_FillContour = cursorInsideContour;

  if (m_FillContour)
  {
    // copy point from float* to mitk::Contour
    Contour::Pointer contourInImageIndexCoordinates = Contour::New();
    contourInImageIndexCoordinates->Initialize();
    Point3D newPoint;
    for (int index = 0; index < numberOfContourPoints; ++index)
    {
      newPoint[0] = contourPoints[ 2 * index + 0 ];
      newPoint[1] = contourPoints[ 2 * index + 1];
      newPoint[2] = 0;

      contourInImageIndexCoordinates->AddVertex( newPoint );
    }

    m_SegmentationContourInWorldCoordinates = SegTool2D::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N

    // 3. Show the contour
    SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );

    SegTool2D::SetFeedbackContourVisible(true);
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  // always generate a second contour, containing the whole image (used when CTRL is pressed)
  {
    // copy point from float* to mitk::Contour
    Contour::Pointer contourInImageIndexCoordinates = Contour::New();
    contourInImageIndexCoordinates->Initialize();
    Point3D newPoint;
    newPoint[0] = 0; newPoint[1] = 0; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = originalPicSlice->n[0]; newPoint[1] = 0; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = originalPicSlice->n[0]; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = 0; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );

    m_WholeImageContourInWorldCoordinates = SegTool2D::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N

    // 3. Show the contour
    SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );

    SegTool2D::SetFeedbackContourVisible(true);
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  free(contourPoints);

  return true;
}

bool mitk::SetRegionTool::OnMouseReleased(Action* action, const StateEvent* stateEvent)
{
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that
  SegTool2D::SetFeedbackContourVisible(false);

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());

  if (!m_FillContour && !m_StatusFillWholeSlice) return true;

  if (!SegTool2D::OnMouseReleased( action, stateEvent )) return false;

  DataTreeNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  int affectedDimension( -1 );
  int affectedSlice( -1 );
  if ( SegTool2D::DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) )
  {
    // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice
    Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image );

    if ( slice.IsNull() )
    {
      std::cerr << "Unable to extract slice." << std::endl;
      return false;
    }

    Contour* feedbackContour( SegTool2D::GetFeedbackContour() );
    Contour::Pointer projectedContour = SegTool2D::ProjectContourTo2DSlice( slice, feedbackContour, false, false ); // false: don't add 0.5 (done by FillContourInSlice)
                                                                                // false: don't constrain the contour to the image's inside
    if (projectedContour.IsNull()) return false;

    SegTool2D::FillContourInSlice( projectedContour, slice, m_PaintingPixelValue );

    // 5. Write the modified 2D working data slice back into the image
    OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New();
    slicewriter->SetInput( image );
    slicewriter->SetCreateUndoInformation( true );
    slicewriter->SetSliceImage( slice );
    slicewriter->SetSliceDimension( affectedDimension );
    slicewriter->SetSliceIndex( affectedSlice );
    slicewriter->Update();

    // 6. Make sure the result is drawn again --> is visible then.
    assert( positionEvent->GetSender()->GetRenderWindow() );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }
  else
  {
    std::cout << "SegTool2D could not determine which slice of the image you are drawing on." << std::endl;
  }

  m_WholeImageContourInWorldCoordinates = NULL;
  m_SegmentationContourInWorldCoordinates = NULL;

  return true;
}

/**
  Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0.
*/
bool mitk::SetRegionTool::OnInvertLogic(Action* action, const StateEvent* stateEvent)
{
  if (!SegTool2D::OnInvertLogic(action, stateEvent)) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  if (m_StatusFillWholeSlice)
  {
    // use contour extracted from image data
    if (m_SegmentationContourInWorldCoordinates.IsNotNull())
      SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }
  else
  {
    // use some artificial contour
    if (m_WholeImageContourInWorldCoordinates.IsNotNull())
      SegTool2D::SetFeedbackContour( *m_WholeImageContourInWorldCoordinates );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  m_StatusFillWholeSlice = !m_StatusFillWholeSlice;

  return true;
}

<commit_msg>FIX (#1185): additional assertion to catch crashed earlier<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSetRegionTool.h"

#include "mitkToolManager.h"
#include "mitkOverwriteSliceImageFilter.h"

#include "ipSegmentation.h"

#include "mitkBaseRenderer.h"

mitk::SetRegionTool::SetRegionTool(int paintingPixelValue)
:SegTool2D("PressMoveReleaseWithCTRLInversion"),
 m_PaintingPixelValue(paintingPixelValue),
 m_FillContour(false),
 m_StatusFillWholeSlice(false)
{
}

mitk::SetRegionTool::~SetRegionTool()
{
}

void mitk::SetRegionTool::Activated()
{
  Superclass::Activated();
}

void mitk::SetRegionTool::Deactivated()
{
  Superclass::Deactivated();
}

bool mitk::SetRegionTool::OnMousePressed (Action* action, const StateEvent* stateEvent)
{
  if (!SegTool2D::OnMousePressed( action, stateEvent )) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  // 1. Get the working image
  Image::Pointer workingSlice   = SegTool2D::GetAffectedWorkingSlice( positionEvent );
  if ( workingSlice.IsNull() ) return false; // can't do anything without the segmentation

  // if click was outside the image, don't continue
  const Geometry3D* sliceGeometry = workingSlice->GetGeometry();
  itk::Index<2> projectedPointIn2D;
  sliceGeometry->WorldToIndex( positionEvent->GetWorldPosition(), projectedPointIn2D );
  if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) )
  {
    std::cout << "point apparently not inside segmentation slice" << std::endl;
    return false; // can't use that as a seed point
  }

    // Convert to ipMITKSegmentationTYPE (because ipMITKSegmentationGetContour8N relys on that data type)
    itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage;
    CastToItkImage( workingSlice, correctPixelTypeImage );
    assert (correctPixelTypeImage.IsNotNull() );

  // possible bug in CastToItkImage ?
  // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in
  // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479:
  // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed
  // solution here: we overwrite it with an unity matrix
  itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection;
  imageDirection.SetIdentity();
  correctPixelTypeImage->SetDirection(imageDirection);

    Image::Pointer temporarySlice = Image::New();
  //  temporarySlice = ImportItkImage( correctPixelTypeImage );
    CastToMitkImage( correctPixelTypeImage, temporarySlice );

  // check index positions
  ipPicDescriptor* originalPicSlice = temporarySlice->GetSliceData()->GetPicDescriptor();

  int m_SeedPointMemoryOffset = projectedPointIn2D[1] * originalPicSlice->n[0] + projectedPointIn2D[0];

  if ( m_SeedPointMemoryOffset >= static_cast<int>( originalPicSlice->n[0] * originalPicSlice->n[1] ) ||
       m_SeedPointMemoryOffset < 0 )
  {
    std::cerr << "Memory offset calculation if mitk::SetRegionTool has some serious flaw! Aborting.." << std::endl;
    return false;
  }

  // 2. Determine the contour that surronds the selected "piece of the image"

  // find a contour seed point
  unsigned int oneContourOffset = static_cast<unsigned int>( m_SeedPointMemoryOffset ); // safe because of earlier check if m_SeedPointMemoryOffset < 0

  /**
    * The logic of finding a starting point for the contour is the following:
    *
    *  - If the initial seed point is 0, we are either inside a hole or outside of every segmentation.
    *    We move to the right until we hit a 1, which must be part of a contour.
    *
    *  - If the initial seed point is 1, then ...
    *    we now do the same (running to the right) until we hit a 1
    *
    *  In both cases the found contour point is used to extract a contour and
    *  then a test is applied to find out if the initial seed point is contained
    *  in the contour. If this is the case, filling should be applied, otherwise
    *  nothing is done.
    */
  unsigned int size = originalPicSlice->n[0] * originalPicSlice->n[1];
/*
  unsigned int rowSize = originalPicSlice->n[0];
*/
  ipMITKSegmentationTYPE* data = static_cast<ipMITKSegmentationTYPE*>(originalPicSlice->data);

  if ( data[oneContourOffset] == 0 ) // initial seed 0
  {
    for ( ; oneContourOffset < size; ++oneContourOffset )
    {
      if ( data[oneContourOffset] > 0 ) break;
    }
  }
  else if ( data[oneContourOffset] == 1 ) // initial seed 1
  {
    unsigned int lastValidPixel = size-1; // initialization, will be changed lateron
    bool inSeg = true;    // inside segmentation?
    for ( ; oneContourOffset < size; ++oneContourOffset )
    {
      if ( ( data[oneContourOffset] == 0 ) && inSeg ) // pixel 0 and inside-flag set: this happens at the first pixel outside a filled region
      {
        inSeg = false;
        lastValidPixel = oneContourOffset - 1; // store the last pixel position inside a filled region
        break;
      }
      else // pixel 1, inside-flag doesn't matter: this happens while we are inside a filled region
      {
        inSeg = true; // first iteration lands here
      }

    }
    oneContourOffset = lastValidPixel;
  }
  else
  {
    std::cerr << "Fill/Erase was never intended to work with other than binary images." << std::endl;
    m_FillContour = false;
    return false;
  }

  if (oneContourOffset == size) // nothing found until end of slice
  {
    m_FillContour = false;
    return false;
  }

  int numberOfContourPoints( 0 );
  int newBufferSize( 0 );
  float* contourPoints = ipMITKSegmentationGetContour8N( originalPicSlice, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc
  assert(contourPoints == NULL && numberOfContourPoints > 0);

  bool cursorInsideContour = ipMITKSegmentationIsInsideContour( contourPoints, numberOfContourPoints, projectedPointIn2D[0], projectedPointIn2D[1]);

  // decide if contour should be filled or not
  m_FillContour = cursorInsideContour;

  if (m_FillContour)
  {
    // copy point from float* to mitk::Contour
    Contour::Pointer contourInImageIndexCoordinates = Contour::New();
    contourInImageIndexCoordinates->Initialize();
    Point3D newPoint;
    for (int index = 0; index < numberOfContourPoints; ++index)
    {
      newPoint[0] = contourPoints[ 2 * index + 0 ];
      newPoint[1] = contourPoints[ 2 * index + 1];
      newPoint[2] = 0;

      contourInImageIndexCoordinates->AddVertex( newPoint );
    }

    m_SegmentationContourInWorldCoordinates = SegTool2D::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N

    // 3. Show the contour
    SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );

    SegTool2D::SetFeedbackContourVisible(true);
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  // always generate a second contour, containing the whole image (used when CTRL is pressed)
  {
    // copy point from float* to mitk::Contour
    Contour::Pointer contourInImageIndexCoordinates = Contour::New();
    contourInImageIndexCoordinates->Initialize();
    Point3D newPoint;
    newPoint[0] = 0; newPoint[1] = 0; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = originalPicSlice->n[0]; newPoint[1] = 0; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = originalPicSlice->n[0]; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );
    newPoint[0] = 0; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0;
    contourInImageIndexCoordinates->AddVertex( newPoint );

    m_WholeImageContourInWorldCoordinates = SegTool2D::BackProjectContourFrom2DSlice( workingSlice, contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N

    // 3. Show the contour
    SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );

    SegTool2D::SetFeedbackContourVisible(true);
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  free(contourPoints);

  return true;
}

bool mitk::SetRegionTool::OnMouseReleased(Action* action, const StateEvent* stateEvent)
{
  // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that
  SegTool2D::SetFeedbackContourVisible(false);

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  assert( positionEvent->GetSender()->GetRenderWindow() );
  mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());

  if (!m_FillContour && !m_StatusFillWholeSlice) return true;

  if (!SegTool2D::OnMouseReleased( action, stateEvent )) return false;

  DataTreeNode* workingNode( m_ToolManager->GetWorkingData(0) );
  if (!workingNode) return false;

  Image* image = dynamic_cast<Image*>(workingNode->GetData());
  const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) );
  if ( !image || !planeGeometry ) return false;

  int affectedDimension( -1 );
  int affectedSlice( -1 );
  if ( SegTool2D::DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) )
  {
    // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice
    Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image );

    if ( slice.IsNull() )
    {
      std::cerr << "Unable to extract slice." << std::endl;
      return false;
    }

    Contour* feedbackContour( SegTool2D::GetFeedbackContour() );
    Contour::Pointer projectedContour = SegTool2D::ProjectContourTo2DSlice( slice, feedbackContour, false, false ); // false: don't add 0.5 (done by FillContourInSlice)
                                                                                // false: don't constrain the contour to the image's inside
    if (projectedContour.IsNull()) return false;

    SegTool2D::FillContourInSlice( projectedContour, slice, m_PaintingPixelValue );

    // 5. Write the modified 2D working data slice back into the image
    OverwriteSliceImageFilter::Pointer slicewriter = OverwriteSliceImageFilter::New();
    slicewriter->SetInput( image );
    slicewriter->SetCreateUndoInformation( true );
    slicewriter->SetSliceImage( slice );
    slicewriter->SetSliceDimension( affectedDimension );
    slicewriter->SetSliceIndex( affectedSlice );
    slicewriter->Update();

    // 6. Make sure the result is drawn again --> is visible then.
    assert( positionEvent->GetSender()->GetRenderWindow() );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }
  else
  {
    std::cout << "SegTool2D could not determine which slice of the image you are drawing on." << std::endl;
  }

  m_WholeImageContourInWorldCoordinates = NULL;
  m_SegmentationContourInWorldCoordinates = NULL;

  return true;
}

/**
  Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0.
*/
bool mitk::SetRegionTool::OnInvertLogic(Action* action, const StateEvent* stateEvent)
{
  if (!SegTool2D::OnInvertLogic(action, stateEvent)) return false;

  const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent());
  if (!positionEvent) return false;

  if (m_StatusFillWholeSlice)
  {
    // use contour extracted from image data
    if (m_SegmentationContourInWorldCoordinates.IsNotNull())
      SegTool2D::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }
  else
  {
    // use some artificial contour
    if (m_WholeImageContourInWorldCoordinates.IsNotNull())
      SegTool2D::SetFeedbackContour( *m_WholeImageContourInWorldCoordinates );
    mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow());
  }

  m_StatusFillWholeSlice = !m_StatusFillWholeSlice;

  return true;
}

<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "pipeline.h"
#include "pipeline_exception.h"

#include "edge.h"

#include <boost/foreach.hpp>

#include <set>

/**
 * \file pipeline.cxx
 *
 * \brief Implementation of the base class for \link pipeline pipelines\endlink.
 */

namespace vistk
{

class pipeline::priv
{
  public:
    priv();
    ~priv();

    typedef std::map<process::name_t, process_t> process_map_t;
    typedef std::pair<process::port_addr_t, process::port_addr_t> connection_t;
    typedef std::vector<connection_t> connections_t;
    typedef std::map<size_t, edge_t> edge_map_t;

    typedef std::map<process::port_t, process::port_addrs_t> input_port_mapping_t;
    typedef std::map<process::port_t, process::port_addr_t> output_port_mapping_t;
    typedef std::pair<input_port_mapping_t, output_port_mapping_t> port_mapping_t;
    typedef std::map<process::name_t, port_mapping_t> group_t;

    connections_t connections;

    process_map_t process_map;
    edge_map_t edge_map;

    group_t groups;
};

pipeline
::pipeline(config_t const& /*config*/)
{
  d = boost::shared_ptr<priv>(new priv);
}

pipeline
::~pipeline()
{
}

void
pipeline
::add_process(process_t process)
{
  if (!process)
  {
    throw null_process_addition();
  }

  process::name_t const name = process->name();

  priv::process_map_t::const_iterator proc_it = d->process_map.find(name);

  if (proc_it != d->process_map.end())
  {
    throw duplicate_process_name(name);
  }

  priv::group_t::const_iterator group_it = d->groups.find(name);

  if (group_it != d->groups.end())
  {
    throw duplicate_process_name(name);
  }

  d->process_map[name] = process;
}

void
pipeline
::add_group(process::name_t const& name)
{
  priv::process_map_t::const_iterator proc_it = d->process_map.find(name);

  if (proc_it != d->process_map.end())
  {
    throw duplicate_process_name(name);
  }

  priv::group_t::const_iterator group_it = d->groups.find(name);

  if (group_it != d->groups.end())
  {
    throw duplicate_process_name(name);
  }

  d->groups[name] = priv::port_mapping_t();
}

void
pipeline
::connect(process::name_t const& upstream_process,
          process::port_t const& upstream_port,
          process::name_t const& downstream_process,
          process::port_t const& downstream_port)
{
  priv::group_t::const_iterator const up_group_it = d->groups.find(upstream_process);

  if (up_group_it != d->groups.end())
  {
    priv::output_port_mapping_t const& mapping = up_group_it->second.second;

    priv::output_port_mapping_t::const_iterator const mapping_it = mapping.find(upstream_port);

    if (mapping_it != mapping.end())
    {
      connect(mapping_it->second.first, mapping_it->second.second,
              downstream_process, downstream_port);

      return;
    }
  }

  priv::group_t::const_iterator const down_group_it = d->groups.find(upstream_process);

  if (down_group_it != d->groups.end())
  {
    priv::input_port_mapping_t const& mapping = down_group_it->second.first;

    priv::input_port_mapping_t::const_iterator const mapping_it = mapping.find(downstream_port);

    if (mapping_it != mapping.end())
    {
      BOOST_FOREACH (process::port_addr_t const& port_addr, mapping_it->second)
      {
        connect(upstream_process, upstream_port,
                port_addr.first, port_addr.second);
      }

      return;
    }
  }

  config_t edge_config = config::empty_config();

  edge_t e = edge_t(new edge(edge_config));

  process::port_addr_t const up_port = process::port_addr_t(upstream_process, upstream_port);
  process::port_addr_t const down_port = process::port_addr_t(downstream_process, downstream_port);
  priv::connection_t const conn = priv::connection_t(up_port, down_port);

  priv::process_map_t::iterator const up_it = d->process_map.find(upstream_process);
  priv::process_map_t::iterator const down_it = d->process_map.find(downstream_process);

  if (up_it == d->process_map.end())
  {
    throw no_such_process(upstream_process);
  }
  if (down_it == d->process_map.end())
  {
    throw no_such_process(downstream_process);
  }

  /// \todo Port type checking here?

  up_it->second->connect_output_port(upstream_port, e);
  down_it->second->connect_input_port(downstream_port, e);

  d->edge_map[d->connections.size()] = e;
  d->connections.push_back(conn);
}

void
pipeline
::map_input_port(process::name_t const& group,
                 process::port_t const& port,
                 process::name_t const& mapped_process,
                 process::port_t const& mapped_port)
{
  priv::group_t::iterator const group_it = d->groups.find(group);

  if (group_it == d->groups.end())
  {
    throw no_such_group(group);
  }

  priv::process_map_t::iterator const proc_it = d->process_map.find(mapped_process);

  if (proc_it == d->process_map.end())
  {
    throw no_such_process(mapped_process);
  }

  priv::input_port_mapping_t& mapping = group_it->second.first;

  mapping[port].push_back(process::port_addr_t(mapped_process, mapped_port));
}

void
pipeline
::map_output_port(process::name_t const& group,
                  process::port_t const& port,
                  process::name_t const& mapped_process,
                  process::port_t const& mapped_port)
{
  priv::group_t::iterator const group_it = d->groups.find(group);

  if (group_it == d->groups.end())
  {
    throw no_such_group(group);
  }

  priv::process_map_t::iterator const proc_it = d->process_map.find(mapped_process);

  if (proc_it == d->process_map.end())
  {
    throw no_such_process(mapped_process);
  }

  priv::output_port_mapping_t& mapping = group_it->second.second;

  priv::output_port_mapping_t::const_iterator const port_it = mapping.find(port);

  if (port_it != mapping.end())
  {
    throw group_output_already_mapped(group, port, port_it->second.first, port_it->second.second, mapped_process, mapped_port);
  }

  mapping[port] = process::port_addr_t(mapped_process, mapped_port);
}

void
pipeline
::setup_pipeline()
{
  /// \todo Check for disconnected pipelines.
  /// \todo Check for types of connections.
  /// \todo Check for required grouping input/output ports (requires flags for ports).
}

process::names_t
pipeline
::process_names() const
{
  process::names_t names;

  BOOST_FOREACH (priv::process_map_t::value_type const& process_index, d->process_map)
  {
    names.push_back(process_index.first);
  }

  return names;
}

process_t
pipeline
::process_by_name(process::name_t const& name) const
{
  priv::process_map_t::const_iterator i = d->process_map.find(name);

  if (i == d->process_map.end())
  {
    throw no_such_process(name);
  }

  return i->second;
}

processes_t
pipeline
::upstream_for_process(process::name_t const& name) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if (connection.second.first == name)
    {
      process::name_t const& upstream_name = connection.first.first;

      process_names.insert(upstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

processes_t
pipeline
::downstream_for_process(process::name_t const& name) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if (connection.first.first == name)
    {
      process::name_t const& downstream_name = connection.second.first;

      process_names.insert(downstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

processes_t
pipeline
::downstream_for_port(process::name_t const& name, process::port_t const& port) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if ((connection.first.first == name) &&
        (connection.first.second == port))
    {
      process::name_t const& downstream_name = connection.second.first;

      process_names.insert(downstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

process::port_addrs_t
pipeline
::receivers_for_port(process::name_t const& name, process::port_t const& port) const
{
  process::port_addrs_t port_addrs;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if ((connection.first.first == name) &&
        (connection.first.second == port))
    {
      process::port_addr_t const& downstream_addr = connection.second;

      port_addrs.push_back(downstream_addr);
    }
  }

  return port_addrs;
}

edges_t
pipeline
::input_edges_for_process(process::name_t const& name) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if (d->connections[edge_index.first].second.first == name)
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

edges_t
pipeline
::output_edges_for_process(process::name_t const& name) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if (d->connections[edge_index.first].first.first == name)
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

edges_t
pipeline
::output_edges_for_port(process::name_t const& name, process::port_t const& port) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if ((d->connections[edge_index.first].first.first == name) &&
        (d->connections[edge_index.first].first.second == port))
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

process::names_t
pipeline
::groups() const
{
  process::names_t names;

  BOOST_FOREACH (priv::group_t::value_type const& group, d->groups)
  {
    process::name_t const& name = group.first;

    names.push_back(name);
  }

  return names;
}

process::ports_t
pipeline
::input_ports_for_group(process::name_t const& name) const
{
  process::ports_t ports;

  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::input_port_mapping_t const& mapping = group_it->second.first;

  BOOST_FOREACH (priv::input_port_mapping_t::value_type const& port_it, mapping)
  {
    process::port_t const& port = port_it.first;

    ports.push_back(port);
  }

  return ports;
}

process::ports_t
pipeline
::output_ports_for_group(process::name_t const& name) const
{
  process::ports_t ports;

  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::output_port_mapping_t const& mapping = group_it->second.second;

  BOOST_FOREACH (priv::output_port_mapping_t::value_type const& port_it, mapping)
  {
    process::port_t const& port = port_it.first;

    ports.push_back(port);
  }

  return ports;
}

process::port_addrs_t
pipeline
::mapped_group_input_ports(process::name_t const& name, process::port_t const& port) const
{
  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::input_port_mapping_t const& mapping = group_it->second.first;

  priv::input_port_mapping_t::const_iterator const mapping_it = mapping.find(port);

  if (mapping_it == mapping.end())
  {
    throw no_such_group_port(name, port);
  }

  return mapping_it->second;
}

process::port_addr_t
pipeline
::mapped_group_output_ports(process::name_t const& name, process::port_t const& port) const
{
  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::output_port_mapping_t const& mapping = group_it->second.second;

  priv::output_port_mapping_t::const_iterator const mapping_it = mapping.find(port);

  if (mapping_it == mapping.end())
  {
    throw no_such_group_port(name, port);
  }

  return mapping_it->second;
}

pipeline::priv
::priv()
{
}

pipeline::priv
::~priv()
{
}

} // end namespace vistk
<commit_msg>Make code more readable (no inline pair access)<commit_after>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "pipeline.h"
#include "pipeline_exception.h"

#include "edge.h"

#include <boost/foreach.hpp>

#include <set>

/**
 * \file pipeline.cxx
 *
 * \brief Implementation of the base class for \link pipeline pipelines\endlink.
 */

namespace vistk
{

class pipeline::priv
{
  public:
    priv();
    ~priv();

    typedef std::map<process::name_t, process_t> process_map_t;
    typedef std::pair<process::port_addr_t, process::port_addr_t> connection_t;
    typedef std::vector<connection_t> connections_t;
    typedef std::map<size_t, edge_t> edge_map_t;

    typedef std::map<process::port_t, process::port_addrs_t> input_port_mapping_t;
    typedef std::map<process::port_t, process::port_addr_t> output_port_mapping_t;
    typedef std::pair<input_port_mapping_t, output_port_mapping_t> port_mapping_t;
    typedef std::map<process::name_t, port_mapping_t> group_t;

    connections_t connections;

    process_map_t process_map;
    edge_map_t edge_map;

    group_t groups;
};

pipeline
::pipeline(config_t const& /*config*/)
{
  d = boost::shared_ptr<priv>(new priv);
}

pipeline
::~pipeline()
{
}

void
pipeline
::add_process(process_t process)
{
  if (!process)
  {
    throw null_process_addition();
  }

  process::name_t const name = process->name();

  priv::process_map_t::const_iterator proc_it = d->process_map.find(name);

  if (proc_it != d->process_map.end())
  {
    throw duplicate_process_name(name);
  }

  priv::group_t::const_iterator group_it = d->groups.find(name);

  if (group_it != d->groups.end())
  {
    throw duplicate_process_name(name);
  }

  d->process_map[name] = process;
}

void
pipeline
::add_group(process::name_t const& name)
{
  priv::process_map_t::const_iterator proc_it = d->process_map.find(name);

  if (proc_it != d->process_map.end())
  {
    throw duplicate_process_name(name);
  }

  priv::group_t::const_iterator group_it = d->groups.find(name);

  if (group_it != d->groups.end())
  {
    throw duplicate_process_name(name);
  }

  d->groups[name] = priv::port_mapping_t();
}

void
pipeline
::connect(process::name_t const& upstream_process,
          process::port_t const& upstream_port,
          process::name_t const& downstream_process,
          process::port_t const& downstream_port)
{
  priv::group_t::const_iterator const up_group_it = d->groups.find(upstream_process);

  if (up_group_it != d->groups.end())
  {
    priv::output_port_mapping_t const& mapping = up_group_it->second.second;

    priv::output_port_mapping_t::const_iterator const mapping_it = mapping.find(upstream_port);

    if (mapping_it != mapping.end())
    {
      connect(mapping_it->second.first, mapping_it->second.second,
              downstream_process, downstream_port);

      return;
    }
  }

  priv::group_t::const_iterator const down_group_it = d->groups.find(upstream_process);

  if (down_group_it != d->groups.end())
  {
    priv::input_port_mapping_t const& mapping = down_group_it->second.first;

    priv::input_port_mapping_t::const_iterator const mapping_it = mapping.find(downstream_port);

    if (mapping_it != mapping.end())
    {
      BOOST_FOREACH (process::port_addr_t const& port_addr, mapping_it->second)
      {
        connect(upstream_process, upstream_port,
                port_addr.first, port_addr.second);
      }

      return;
    }
  }

  config_t edge_config = config::empty_config();

  edge_t e = edge_t(new edge(edge_config));

  process::port_addr_t const up_port = process::port_addr_t(upstream_process, upstream_port);
  process::port_addr_t const down_port = process::port_addr_t(downstream_process, downstream_port);
  priv::connection_t const conn = priv::connection_t(up_port, down_port);

  priv::process_map_t::iterator const up_it = d->process_map.find(upstream_process);
  priv::process_map_t::iterator const down_it = d->process_map.find(downstream_process);

  if (up_it == d->process_map.end())
  {
    throw no_such_process(upstream_process);
  }
  if (down_it == d->process_map.end())
  {
    throw no_such_process(downstream_process);
  }

  /// \todo Port type checking here?

  process_t const& up_proc = up_it->second;
  process_t const& down_proc = down_it->second;

  up_proc->connect_output_port(upstream_port, e);
  down_proc->connect_input_port(downstream_port, e);

  d->edge_map[d->connections.size()] = e;
  d->connections.push_back(conn);
}

void
pipeline
::map_input_port(process::name_t const& group,
                 process::port_t const& port,
                 process::name_t const& mapped_process,
                 process::port_t const& mapped_port)
{
  priv::group_t::iterator const group_it = d->groups.find(group);

  if (group_it == d->groups.end())
  {
    throw no_such_group(group);
  }

  priv::process_map_t::iterator const proc_it = d->process_map.find(mapped_process);

  if (proc_it == d->process_map.end())
  {
    throw no_such_process(mapped_process);
  }

  priv::input_port_mapping_t& mapping = group_it->second.first;

  mapping[port].push_back(process::port_addr_t(mapped_process, mapped_port));
}

void
pipeline
::map_output_port(process::name_t const& group,
                  process::port_t const& port,
                  process::name_t const& mapped_process,
                  process::port_t const& mapped_port)
{
  priv::group_t::iterator const group_it = d->groups.find(group);

  if (group_it == d->groups.end())
  {
    throw no_such_group(group);
  }

  priv::process_map_t::iterator const proc_it = d->process_map.find(mapped_process);

  if (proc_it == d->process_map.end())
  {
    throw no_such_process(mapped_process);
  }

  priv::output_port_mapping_t& mapping = group_it->second.second;

  priv::output_port_mapping_t::const_iterator const port_it = mapping.find(port);

  if (port_it != mapping.end())
  {
    throw group_output_already_mapped(group, port, port_it->second.first, port_it->second.second, mapped_process, mapped_port);
  }

  mapping[port] = process::port_addr_t(mapped_process, mapped_port);
}

void
pipeline
::setup_pipeline()
{
  /// \todo Check for disconnected pipelines.
  /// \todo Check for types of connections.
  /// \todo Check for required grouping input/output ports (requires flags for ports).
}

process::names_t
pipeline
::process_names() const
{
  process::names_t names;

  BOOST_FOREACH (priv::process_map_t::value_type const& process_index, d->process_map)
  {
    names.push_back(process_index.first);
  }

  return names;
}

process_t
pipeline
::process_by_name(process::name_t const& name) const
{
  priv::process_map_t::const_iterator i = d->process_map.find(name);

  if (i == d->process_map.end())
  {
    throw no_such_process(name);
  }

  return i->second;
}

processes_t
pipeline
::upstream_for_process(process::name_t const& name) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if (connection.second.first == name)
    {
      process::name_t const& upstream_name = connection.first.first;

      process_names.insert(upstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

processes_t
pipeline
::downstream_for_process(process::name_t const& name) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if (connection.first.first == name)
    {
      process::name_t const& downstream_name = connection.second.first;

      process_names.insert(downstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

processes_t
pipeline
::downstream_for_port(process::name_t const& name, process::port_t const& port) const
{
  std::set<process::name_t> process_names;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if ((connection.first.first == name) &&
        (connection.first.second == port))
    {
      process::name_t const& downstream_name = connection.second.first;

      process_names.insert(downstream_name);
    }
  }

  processes_t processes;

  BOOST_FOREACH (process::name_t const& process_name, process_names)
  {
    priv::process_map_t::const_iterator i = d->process_map.find(process_name);

    processes.push_back(i->second);
  }

  return processes;
}

process::port_addrs_t
pipeline
::receivers_for_port(process::name_t const& name, process::port_t const& port) const
{
  process::port_addrs_t port_addrs;

  BOOST_FOREACH (priv::connection_t const& connection, d->connections)
  {
    if ((connection.first.first == name) &&
        (connection.first.second == port))
    {
      process::port_addr_t const& downstream_addr = connection.second;

      port_addrs.push_back(downstream_addr);
    }
  }

  return port_addrs;
}

edges_t
pipeline
::input_edges_for_process(process::name_t const& name) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if (d->connections[edge_index.first].second.first == name)
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

edges_t
pipeline
::output_edges_for_process(process::name_t const& name) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if (d->connections[edge_index.first].first.first == name)
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

edges_t
pipeline
::output_edges_for_port(process::name_t const& name, process::port_t const& port) const
{
  edges_t edges;

  BOOST_FOREACH (priv::edge_map_t::value_type const& edge_index, d->edge_map)
  {
    if ((d->connections[edge_index.first].first.first == name) &&
        (d->connections[edge_index.first].first.second == port))
    {
      edges.push_back(edge_index.second);
    }
  }

  return edges;
}

process::names_t
pipeline
::groups() const
{
  process::names_t names;

  BOOST_FOREACH (priv::group_t::value_type const& group, d->groups)
  {
    process::name_t const& name = group.first;

    names.push_back(name);
  }

  return names;
}

process::ports_t
pipeline
::input_ports_for_group(process::name_t const& name) const
{
  process::ports_t ports;

  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::input_port_mapping_t const& mapping = group_it->second.first;

  BOOST_FOREACH (priv::input_port_mapping_t::value_type const& port_it, mapping)
  {
    process::port_t const& port = port_it.first;

    ports.push_back(port);
  }

  return ports;
}

process::ports_t
pipeline
::output_ports_for_group(process::name_t const& name) const
{
  process::ports_t ports;

  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::output_port_mapping_t const& mapping = group_it->second.second;

  BOOST_FOREACH (priv::output_port_mapping_t::value_type const& port_it, mapping)
  {
    process::port_t const& port = port_it.first;

    ports.push_back(port);
  }

  return ports;
}

process::port_addrs_t
pipeline
::mapped_group_input_ports(process::name_t const& name, process::port_t const& port) const
{
  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::input_port_mapping_t const& mapping = group_it->second.first;

  priv::input_port_mapping_t::const_iterator const mapping_it = mapping.find(port);

  if (mapping_it == mapping.end())
  {
    throw no_such_group_port(name, port);
  }

  return mapping_it->second;
}

process::port_addr_t
pipeline
::mapped_group_output_ports(process::name_t const& name, process::port_t const& port) const
{
  priv::group_t::const_iterator const group_it = d->groups.find(name);

  if (group_it == d->groups.end())
  {
    throw no_such_group(name);
  }

  priv::output_port_mapping_t const& mapping = group_it->second.second;

  priv::output_port_mapping_t::const_iterator const mapping_it = mapping.find(port);

  if (mapping_it == mapping.end())
  {
    throw no_such_group_port(name, port);
  }

  return mapping_it->second;
}

pipeline::priv
::priv()
{
}

pipeline::priv
::~priv()
{
}

} // end namespace vistk
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/SnapshotManager.h>
#include <vw/Plate/detail/MipmapHelpers.h>
#include <vw/Plate/PlateFile.h>
#include <vw/Plate/TileManipulation.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Image/ImageView.h>
#include <boost/foreach.hpp>
#include <boost/lambda/construct.hpp>

namespace d = vw::platefile::detail;

namespace {
  using namespace vw;
  using namespace vw::platefile;

  // row, col at target level, tile headers from next level down (sorted in Tid order)
  typedef std::map<d::rowcol_t, std::vector<TileHeader> > composite_map_t;
  // Cache of parsed images
  template <typename PixelT>
  struct tile_cache_t : public std::map<d::rowcoltid_t, ImageView<PixelT> > {};

  template <typename PixelT>
  void parse_image_and_store(const Tile& t, tile_cache_t<PixelT>& tile_cache) {
    ImageView<PixelT>& image = tile_cache[d::rowcoltid_t(t.hdr.row(), t.hdr.col(), t.hdr.transaction_id())];
    boost::scoped_ptr<SrcImageResource> r(SrcMemoryImageResource::open(t.hdr.filetype(), &t.data->operator[](0), t.data->size()));
    read_image(image, *r);
  }

  template <typename PixelT>
  void mosaic_in_tid_order(ImageView<PixelT>& out, const size_t size, const tile_cache_t<PixelT>& tile_cache, std::vector<TileHeader>& tiles) {
    typedef ImageView<PixelT> image_t;
    typedef tile_cache_t<PixelT> cache_t;

    std::sort(tiles.begin(), tiles.end(), d::SortByTid());
    mosaic::ImageComposite<PixelT> composite;
    composite.set_draft_mode(true);
    // Insert the images into the composite from lowest to highest tid
    BOOST_FOREACH(const TileHeader& hdr, tiles) {
      typename cache_t::const_iterator i = tile_cache.find(d::rowcoltid_t(d::therow(hdr), d::thecol(hdr), d::thetid(hdr)));
      if (i == tile_cache.end()) {
        vw_out(WarningMessage, "platefile.snapshot") << "Failed to load image for " << hdr << std::endl;
        continue;
      }
      composite.insert(i->second, 0, 0);
      if (is_opaque(i->second))
        break;
    }
    if (composite.cols() == 0 || composite.rows() == 0) {
      out.reset();
      return;
    }
    composite.prepare(BBox2i(0,0,size,size));
    out = composite;
  }
}

namespace vw {
namespace platefile {

template <class PixelT>
void SnapshotManager<PixelT>::snapshot(uint32 level, BBox2i const& tile_region, TransactionRange range, const ProgressCallback &progress) const {
  // The byte size of an uncompressed image
  const uint64 TILE_BYTES  = m_write_plate->default_tile_size() * m_write_plate->default_tile_size() * uint32(PixelNumBytes<PixelT>::value);
  const uint64 CACHE_BYTES = vw_settings().system_cache_size();
  const uint64 CACHE_TILES = CACHE_BYTES / TILE_BYTES;
  VW_ASSERT( CACHE_TILES > 1, LogicErr() << "Cache too small to process any tiles in snapshot." );
  // This is an arbitrary value, to hopefully catch
  // pathlogically-small cache sizes
  if ( CACHE_TILES < 100 )
    vw_out(WarningMessage) << "You will lose a lot speed to thrashing if you can't cache at least 100 tiles (you can only store " << CACHE_TILES << ")\n";

  // Divide up the region into moderately-sized chunks
  std::list<BBox2i> regions = bbox_tiles(tile_region, 1024, 1024);
  BOOST_FOREACH(const BBox2i& region, regions) {
    SubProgressCallback region_pc(progress, progress.progress(), progress.progress() + 1./regions.size());

    // This map holds the headers for the current level
    composite_map_t composite_map;

    // Grab the tiles in the zone
    BOOST_FOREACH(const TileHeader& hdr, m_read_plate->search_by_region(level, region, range))
      composite_map[d::rowcol_t(hdr.row(), hdr.col())].push_back(hdr);

    if (composite_map.size() == 0) {
      region_pc.report_finished();
      continue;
    }

    d::RememberCallback pc(region_pc, 1, composite_map.size());

    composite_map_t::const_iterator i = composite_map.begin(), end = composite_map.end();

    do {
      // queue up CACHE_TILES worth of tiles into composite_batch
      size_t size = 0;
      composite_map_t composite_batch;

      composite_map_t::const_iterator i_before = i;
      for (; i != end; ++i) {
        if (size + i->second.size() <= CACHE_TILES) {
          composite_batch.insert(*i);
          size += i->second.size();
        } else {
          VW_ASSERT( i_before != i,
                     LogicErr() << "Cache too small to perform composite. Stuck in infinite loop." );
          break;
        }
      }
      if (composite_batch.size() == 0)
        continue;

      Datastore::TileSearch tile_lookup;
      tile_cache_t<PixelT> tile_cache;

      BOOST_FOREACH(const composite_map_t::value_type& t, composite_batch) {
        //std::cerr << "Batching tiles for " << t.first << ": ";
        //std::transform(t.second.begin(), t.second.end(), std::ostream_iterator<uint32>(std::cerr, ", "), boost::bind(&TileHeader::transaction_id, _1));
        //std::cerr << " (currently have " << tile_lookup.size() << "/" << CACHE_TILES << ")" << std::endl;
        std::copy(t.second.begin(), t.second.end(), std::back_inserter(tile_lookup));
      }

      BOOST_FOREACH(const Tile& t, m_read_plate->batch_read(tile_lookup))
        parse_image_and_store(t, tile_cache);
      tile_lookup.clear();

      BOOST_FOREACH(composite_map_t::value_type& t, composite_batch) {
        ImageView<PixelT> tile;
        mosaic_in_tid_order<PixelT>(tile, m_write_plate->default_tile_size(), tile_cache, t.second);
        if (!tile) {
          vw_out(WarningMessage, "platefile.snapshot") << "Empty tile list, skipping writing tile row=" << d::therow(t.first) << " col=" << d::thecol(t.first) << std::endl;
          continue;
        }
        m_write_plate->write_update(tile, d::thecol(t.first), d::therow(t.first), level);
        pc.tick();
      }
      composite_batch.clear();
      size = 0;
    } while (i != end);
    region_pc.report_finished();
  }
  progress.report_finished();
}

// Create a full snapshot of every level and every region in the mosaic.
template <class PixelT>
void SnapshotManager<PixelT>::full_snapshot(TransactionRange read_transaction_range) const {
  for (int32 level = m_read_plate->num_levels()-1; level >= 0; --level) {
    TerminalProgressCallback prog("plate.snapshot", std::string("Snapshot level ") + stringify(level));
    snapshot(level, d::move_down(BBox2i(0,0,1,1), level), read_transaction_range, prog);
  }
}

}} // namespace vw::platefile

// Explicit template instatiation
#define _VW_INSTANTIATE(Px)\
  template\
  void vw::platefile::SnapshotManager<Px >::snapshot(uint32 level, BBox2i const& bbox, TransactionRange, const ProgressCallback &progress) const;\
  template\
  void vw::platefile::SnapshotManager<Px >::full_snapshot(TransactionRange) const;

_VW_INSTANTIATE(vw::PixelGrayA<vw::uint8>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::int16>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::float32>);
_VW_INSTANTIATE(vw::PixelRGBA<vw::uint8>);
<commit_msg>Fix snapshot issue found in CTX Mosaic<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/SnapshotManager.h>
#include <vw/Plate/detail/MipmapHelpers.h>
#include <vw/Plate/PlateFile.h>
#include <vw/Plate/TileManipulation.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Image/ImageView.h>
#include <vw/Image/UtilityViews.h>
#include <boost/foreach.hpp>
#include <boost/lambda/construct.hpp>

namespace d = vw::platefile::detail;

namespace {
  using namespace vw;
  using namespace vw::platefile;

  // row, col at target level, tile headers from next level down (sorted in Tid order)
  typedef std::map<d::rowcol_t, std::vector<TileHeader> > composite_map_t;
  // Cache of parsed images
  template <typename PixelT>
  struct tile_cache_t : public std::map<d::rowcoltid_t, ImageView<PixelT> > {};

  template <typename PixelT>
  void parse_image_and_store(const Tile& t, tile_cache_t<PixelT>& tile_cache) {
    ImageView<PixelT>& image = tile_cache[d::rowcoltid_t(t.hdr.row(), t.hdr.col(), t.hdr.transaction_id())];
    boost::scoped_ptr<SrcImageResource> r(SrcMemoryImageResource::open(t.hdr.filetype(), &t.data->operator[](0), t.data->size()));
    read_image(image, *r);
  }

  template <typename PixelT>
  void mosaic_in_tid_order(ImageView<PixelT>& out, const size_t size, const tile_cache_t<PixelT>& tile_cache, std::vector<TileHeader>& tiles) {
    typedef ImageView<PixelT> image_t;
    typedef tile_cache_t<PixelT> cache_t;

    // We arrange in descending order, so that when the higher level
    // tiles fill the output completely, we'll stop inserting.
    out = constant_view(PixelT(), size, size);
    std::sort(tiles.begin(), tiles.end(), d::SortByTidDesc());
    // Insert the images into the composite from lowest to highest tid
    BOOST_FOREACH(const TileHeader& hdr, tiles) {
      typename cache_t::const_iterator i = tile_cache.find(d::rowcoltid_t(d::therow(hdr), d::thecol(hdr), d::thetid(hdr)));
      if (i == tile_cache.end()) {
        vw_out(WarningMessage, "platefile.snapshot") << "Failed to load image for " << hdr << std::endl;
        continue;
      }

      // Insert the next lower tile and then lay the previous
      // composite on top. If this new combination is opaque, we've
      // finished the snapshot.
      mosaic::ImageComposite<PixelT> composite;
      composite.set_draft_mode(true);
      composite.insert(i->second, 0, 0);
      composite.insert( out, 0, 0 );
      composite.prepare(BBox2i(0,0,size,size));
      out = composite;
      if ( is_opaque( out ) )
        return;
    }
  }
}

namespace vw {
namespace platefile {

template <class PixelT>
void SnapshotManager<PixelT>::snapshot(uint32 level, BBox2i const& tile_region, TransactionRange range, const ProgressCallback &progress) const {
  // The byte size of an uncompressed image
  const uint64 TILE_BYTES  = m_write_plate->default_tile_size() * m_write_plate->default_tile_size() * uint32(PixelNumBytes<PixelT>::value);
  const uint64 CACHE_BYTES = vw_settings().system_cache_size();
  const uint64 CACHE_TILES = CACHE_BYTES / TILE_BYTES;
  VW_ASSERT( CACHE_TILES > 1, LogicErr() << "Cache too small to process any tiles in snapshot." );
  // This is an arbitrary value, to hopefully catch
  // pathlogically-small cache sizes
  if ( CACHE_TILES < 100 )
    vw_out(WarningMessage) << "You will lose a lot speed to thrashing if you can't cache at least 100 tiles (you can only store " << CACHE_TILES << ")\n";

  // Divide up the region into moderately-sized chunks
  std::list<BBox2i> regions = bbox_tiles(tile_region, 1024, 1024);
  BOOST_FOREACH(const BBox2i& region, regions) {
    SubProgressCallback region_pc(progress, progress.progress(), progress.progress() + 1./regions.size());

    // This map holds the headers for the current level
    composite_map_t composite_map;

    // Grab the tiles in the zone
    BOOST_FOREACH(const TileHeader& hdr, m_read_plate->search_by_region(level, region, range))
      composite_map[d::rowcol_t(hdr.row(), hdr.col())].push_back(hdr);

    if (composite_map.size() == 0) {
      region_pc.report_finished();
      continue;
    }

    d::RememberCallback pc(region_pc, 1, composite_map.size());

    composite_map_t::const_iterator i = composite_map.begin(), end = composite_map.end();

    do {
      // queue up CACHE_TILES worth of tiles into composite_batch
      size_t size = 0;
      composite_map_t composite_batch;

      composite_map_t::const_iterator i_before = i;
      for (; i != end; ++i) {
        if (size + i->second.size() <= CACHE_TILES) {
          composite_batch.insert(*i);
          size += i->second.size();
        } else {
          VW_ASSERT( i_before != i,
                     LogicErr() << "Cache too small to perform composite. Stuck in infinite loop." );
          break;
        }
      }
      if (composite_batch.size() == 0)
        continue;

      Datastore::TileSearch tile_lookup;
      tile_cache_t<PixelT> tile_cache;

      BOOST_FOREACH(const composite_map_t::value_type& t, composite_batch) {
        //std::cerr << "Batching tiles for " << t.first << ": ";
        //std::transform(t.second.begin(), t.second.end(), std::ostream_iterator<uint32>(std::cerr, ", "), boost::bind(&TileHeader::transaction_id, _1));
        //std::cerr << " (currently have " << tile_lookup.size() << "/" << CACHE_TILES << ")" << std::endl;
        std::copy(t.second.begin(), t.second.end(), std::back_inserter(tile_lookup));
      }

      BOOST_FOREACH(const Tile& t, m_read_plate->batch_read(tile_lookup))
        parse_image_and_store(t, tile_cache);
      tile_lookup.clear();

      BOOST_FOREACH(composite_map_t::value_type& t, composite_batch) {

        // Early exit condition if there is only one tile
        if (t.second.size() == 1 ) {
          typename tile_cache_t<PixelT>::const_iterator i =
            tile_cache.find(d::rowcoltid_t(d::therow(t.second[0]), d::thecol(t.second[0]), d::thetid(t.second[0])));
          if ( i == tile_cache.end() ) {
            vw_out(WarningMessage, "platefile.snapshot") << "Failed to load image for " << t.second[0] << std::endl;
            continue;
          }
          m_write_plate->write_update(i->second, d::thecol(t.first), d::therow(t.first), level);
          continue;
        }

        // Perform an actual composite if there are multiple tiles to be inserted
        ImageView<PixelT> tile;
        mosaic_in_tid_order<PixelT>(tile, m_write_plate->default_tile_size(), tile_cache, t.second);
        if (!tile) {
          vw_out(WarningMessage, "platefile.snapshot") << "Empty tile list, skipping writing tile row=" << d::therow(t.first) << " col=" << d::thecol(t.first) << std::endl;
          continue;
        }
        m_write_plate->write_update(tile, d::thecol(t.first), d::therow(t.first), level);
        pc.tick();
      }
      composite_batch.clear();
      size = 0;
    } while (i != end);
    region_pc.report_finished();
  }
  progress.report_finished();
}

// Create a full snapshot of every level and every region in the mosaic.
template <class PixelT>
void SnapshotManager<PixelT>::full_snapshot(TransactionRange read_transaction_range) const {
  for (int32 level = m_read_plate->num_levels()-1; level >= 0; --level) {
    TerminalProgressCallback prog("plate.snapshot", std::string("Snapshot level ") + stringify(level));
    snapshot(level, d::move_down(BBox2i(0,0,1,1), level), read_transaction_range, prog);
  }
}

}} // namespace vw::platefile

// Explicit template instatiation
#define _VW_INSTANTIATE(Px)\
  template\
  void vw::platefile::SnapshotManager<Px >::snapshot(uint32 level, BBox2i const& bbox, TransactionRange, const ProgressCallback &progress) const;\
  template\
  void vw::platefile::SnapshotManager<Px >::full_snapshot(TransactionRange) const;

_VW_INSTANTIATE(vw::PixelGrayA<vw::uint8>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::int16>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::float32>);
_VW_INSTANTIATE(vw::PixelRGBA<vw::uint8>);
<|endoftext|>