<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: chips/p9/procedures/hwp/memory/p9_mss_scrub.C $               */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* EKB Project                                                            */
/*                                                                        */
/* COPYRIGHT 2015,2016                                                    */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_scrub.C
/// @brief Begin background scrub
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mss_scrub.H>

#include <lib/dimm/rank.H>
#include <lib/mcbist/address.H>
#include <lib/mcbist/mcbist.H>
#include <lib/dimm/kind.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::FAPI2_RC_SUCCESS;

///
/// @brief Begin background scrub
/// @param[in] i_target MCBIST
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode p9_mss_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("Start mss scrub");

    // If we're running in the simulator, we want to only touch the addresses which training touched
    uint8_t is_sim = 0;
    FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );

    for (const auto& p : i_target.getChildren<TARGET_TYPE_MCA>())
    {
        std::vector<uint64_t> l_pr;
        mss::mcbist::program<TARGET_TYPE_MCBIST> l_program;

        // In sim we know a few things ...
        // Get the primary ranks for this port. We know there can only be 4, and we know we only trained the primary
        // ranks. Therefore, we only need to clean up the primary ranks. And because there's 4 max, we can do it
        // all using the 4 address range registers of tne MCBIST (broadcast currently not considered.)
        // So we can write 0's to those to get their ECC fixed up.
        FAPI_TRY( mss::primary_ranks(p, l_pr) );

        for (const auto& r : l_pr)
        {
            mss::mcbist::address l_start;
            mss::mcbist::address l_end;

            // Setup l_start to represent this rank, and then make the end address from that.
            l_start.set_master_rank(r);

            // For checking 8Gb DRAM, add row 16 to the mix - should see valid traffic in the AET
            l_start.set_row(0b10);

            // l_end starts like as the max as we want to scrub the entire thing. If we're in sim,
            // we'll wratchet that back.
            l_start.get_range<mss::mcbist::address::MRANK>(l_end);

            if (is_sim)
            {
                l_start.get_range<mss::mcbist::address::COL>(l_end);
                // Set C3 bit to get an entire cache line
                l_end.set_field<mss::mcbist::address::COL>(0b1000000);
            }

            // By default we're in maint address mode, not address counting mode. So we give it a start and end, and ignore
            // anything invalid - that's what maint address mode is all about
//            mss::mcbist::config_address_range(i_target, l_start, l_end, r);
            mss::mcbist::config_address_range(i_target, l_start, l_start + 4, r);

            // Write
            {
                // Run in ECC mode, 64B writes (superfast mode)

                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fw_subtest =
                    mss::mcbist::write_subtest<TARGET_TYPE_MCBIST>();

                l_fw_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fw_subtest.change_addr_sel(r);
                l_fw_subtest.enable_dimm(mss::get_dimm_from_rank(r));
                l_program.iv_subtests.push_back(l_fw_subtest);
                FAPI_DBG("adding superfast write for %s rank %d (dimm %d)", mss::c_str(p), r, mss::get_dimm_from_rank(r));
            }

            // Read
            {
                // Run in ECC mode, 64B writes (superfast mode)
                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fr_subtest =
                    mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>();

                l_fr_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fr_subtest.change_addr_sel(r);
                l_fr_subtest.enable_dimm(mss::get_dimm_from_rank(r));
                l_program.iv_subtests.push_back(l_fr_subtest);
                FAPI_DBG("adding superfast read for %s rank %d (dimm %d)", mss::c_str(p), r, mss::get_dimm_from_rank(r));
            }
        }

        // Write pattern
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD0Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD1Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD2Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD3Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD4Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD5Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD6Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD7Q, 0x1234567890ABCDEF) );

        // Setup the sim polling based on a heuristic <cough>guess</cough>
        // Looks like ~250ck per address for a write/read program on the sim-dimm, and add a long number of polls
        // and a 64x fudge factor. Testing shows this takes about 50 or so poll loops to complete, which is ok
        l_program.iv_poll.iv_initial_sim_delay = mss::cycles_to_simcycles((64 * l_pr.size()) * 250);
        l_program.iv_poll.iv_delay = 200;

        // On real hardware wait 100ms and then start polling for another 5s
        l_program.iv_poll.iv_initial_delay = 100 * mss::DELAY_1MS;
        l_program.iv_poll.iv_delay = 10 * mss::DELAY_1MS;

        l_program.iv_poll.iv_poll_count = 500;

        // Just one port for now. Per Shelton we need to set this in maint address mode
        // even tho we specify the port/dimm in the subtest.
        fapi2::buffer<uint8_t> l_port;
        l_port.setBit(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
        l_program.select_ports(l_port >> 4);

        // Kick it off, wait for a result
        FAPI_TRY( mss::mcbist::execute(i_target, l_program) );
    }

fapi_try_exit:
    FAPI_INF("End mss scrub");
    return fapi2::current_err;
}
<commit_msg>Fix p9_mss_scrub (sim only) for 4 port configs<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: chips/p9/procedures/hwp/memory/p9_mss_scrub.C $               */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* EKB Project                                                            */
/*                                                                        */
/* COPYRIGHT 2015,2016                                                    */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_scrub.C
/// @brief Begin background scrub
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mss_scrub.H>

#include <lib/dimm/rank.H>
#include <lib/mcbist/address.H>
#include <lib/mcbist/mcbist.H>
#include <lib/dimm/kind.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::FAPI2_RC_SUCCESS;

///
/// @brief Begin background scrub
/// @param[in] i_target MCBIST
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode p9_mss_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("Start mss scrub");

    // If we're running in the simulator, we want to only touch the addresses which training touched
    uint8_t is_sim = 0;
    FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_IS_SIMULATION, fapi2::Target<TARGET_TYPE_SYSTEM>(), is_sim) );

    for (const auto& p : i_target.getChildren<TARGET_TYPE_MCA>())
    {
        std::vector<uint64_t> l_pr;
        mss::mcbist::program<TARGET_TYPE_MCBIST> l_program;

        mss::mcbist::address l_start;
        mss::mcbist::address l_end;

        size_t l_rank_address_pair = 0;

        // In sim we know a few things ...
        // Get the primary ranks for this port. We know there can only be 4, and we know we only trained the primary
        // ranks. Therefore, we only need to clean up the primary ranks. And because there's 4 max, we can do it
        // all using the 4 address range registers of tne MCBIST (broadcast currently not considered.)
        // So we can write 0's to those to get their ECC fixed up.
        FAPI_TRY( mss::primary_ranks(p, l_pr) );
        fapi2::Assert( l_pr.size() <= mss::MAX_RANK_PER_DIMM);

        for (auto r = l_pr.begin(); r != l_pr.end(); ++l_rank_address_pair, ++r)
        {
            // Setup l_start to represent this rank, and then make the end address from that.
            l_start.set_master_rank(*r);

            // l_end starts like as the max as we want to scrub the entire thing. If we're in sim,
            // we'll wratchet that back.
            l_start.get_range<mss::mcbist::address::MRANK>(l_end);

            if (is_sim)
            {
                l_start.get_range<mss::mcbist::address::COL>(l_end);
                // Set C3 bit to get an entire cache line
                l_end.set_field<mss::mcbist::address::COL>(0b1000000);
            }

            // By default we're in maint address mode, not address counting mode. So we give it a start and end, and ignore
            // anything invalid - that's what maint address mode is all about
            mss::mcbist::config_address_range(i_target, l_start, l_end, l_rank_address_pair);

            // Write
            {
                // Run in ECC mode, 64B writes (superfast mode)

                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fw_subtest =
                    mss::mcbist::write_subtest<TARGET_TYPE_MCBIST>();

                l_fw_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fw_subtest.change_addr_sel(l_rank_address_pair);
                l_fw_subtest.enable_dimm(mss::get_dimm_from_rank(*r));
                l_program.iv_subtests.push_back(l_fw_subtest);
                FAPI_DBG("adding superfast write for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r));
            }

            // Read
            {
                // Run in ECC mode, 64B writes (superfast mode)
                mss::mcbist::subtest_t<TARGET_TYPE_MCBIST> l_fr_subtest =
                    mss::mcbist::read_subtest<TARGET_TYPE_MCBIST>();

                l_fr_subtest.enable_port(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
                l_fr_subtest.change_addr_sel(l_rank_address_pair);
                l_fr_subtest.enable_dimm(mss::get_dimm_from_rank(*r));
                l_program.iv_subtests.push_back(l_fr_subtest);
                FAPI_DBG("adding superfast read for %s rank %d (dimm %d)", mss::c_str(p), *r, mss::get_dimm_from_rank(*r));
            }
        }

        // Write pattern
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD0Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD1Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD2Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD3Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD4Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD5Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD6Q, 0x1234567890ABCDEF) );
        FAPI_TRY( mss::putScom(i_target, MCBIST_MCBFD7Q, 0x1234567890ABCDEF) );

        // Setup the sim polling based on a heuristic <cough>guess</cough>
        // Looks like ~400ck per address for a write/read program on the sim-dimm, and add a long number of polls
        // On real hardware wait 100ms and then start polling for another 5s
        l_program.iv_poll.iv_initial_sim_delay = mss::cycles_to_simcycles(((l_end - l_start) * l_pr.size()) * 800);
        l_program.iv_poll.iv_initial_delay = 100 * mss::DELAY_1MS;
        l_program.iv_poll.iv_sim_delay = 100000;
        l_program.iv_poll.iv_delay = 10 * mss::DELAY_1MS;
        l_program.iv_poll.iv_poll_count = 500;

        // Just one port for now. Per Shelton we need to set this in maint address mode
        // even tho we specify the port/dimm in the subtest.
        fapi2::buffer<uint8_t> l_port;
        l_port.setBit(mss::relative_pos<TARGET_TYPE_MCBIST>(p));
        l_program.select_ports(l_port >> 4);

        // Kick it off, wait for a result
        FAPI_TRY( mss::mcbist::execute(i_target, l_program) );
    }

fapi_try_exit:
    FAPI_INF("End mss scrub");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: simplemapi.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 14:24:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef INCLUDED_SIMPLEMAPI_HXX
#define INCLUDED_SIMPLEMAPI_HXX

#define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <windows.h>
#include <mapi.h>
#include <mapix.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif

class CSimpleMapi
{
public:
    /**
        @throws std::runtime_error
        if either the mapi32.dll could not be loaded at all
        or necessary function exports are missing
    */
    CSimpleMapi(); // throws std::runtime_error;

    ~CSimpleMapi();

    ULONG MAPILogon(
        ULONG ulUIParam,
        LPTSTR lpszProfileName,
        LPTSTR lpszPassword,
        FLAGS flFlags,
        ULONG ulReserved,
        LPLHANDLE lplhSession );

    ULONG MAPILogoff(
        LHANDLE lhSession,
        ULONG ulUIParam,
        FLAGS flFlags,
        ULONG ulReserved );

    ULONG MAPISendMail(
        LHANDLE lhSession,
        ULONG ulUIParam,
        lpMapiMessage lpMessage,
        FLAGS flFlags,
        ULONG ulReserved );

private:
    HMODULE         m_hMapiDll;
    LPMAPILOGON     m_lpfnMapiLogon;
    LPMAPILOGOFF    m_lpfnMapiLogoff;
    LPMAPISENDMAIL  m_lpfnMapiSendMail;
};

#endif
<commit_msg>INTEGRATION: CWS mingwport03 (1.4.32); FILE MERGED 2006/09/07 14:32:54 vg 1.4.32.1: #i53572# MinGW port<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: simplemapi.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2007-03-26 13:51:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef INCLUDED_SIMPLEMAPI_HXX
#define INCLUDED_SIMPLEMAPI_HXX

#define WIN32_LEAN_AND_MEAN
#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <windows.h>
#include <mapi.h>
#ifndef __MINGW32__
#include <mapix.h>
#endif
#if defined _MSC_VER
#pragma warning(pop)
#endif

class CSimpleMapi
{
public:
    /**
        @throws std::runtime_error
        if either the mapi32.dll could not be loaded at all
        or necessary function exports are missing
    */
    CSimpleMapi(); // throws std::runtime_error;

    ~CSimpleMapi();

    ULONG MAPILogon(
        ULONG ulUIParam,
        LPTSTR lpszProfileName,
        LPTSTR lpszPassword,
        FLAGS flFlags,
        ULONG ulReserved,
        LPLHANDLE lplhSession );

    ULONG MAPILogoff(
        LHANDLE lhSession,
        ULONG ulUIParam,
        FLAGS flFlags,
        ULONG ulReserved );

    ULONG MAPISendMail(
        LHANDLE lhSession,
        ULONG ulUIParam,
        lpMapiMessage lpMessage,
        FLAGS flFlags,
        ULONG ulReserved );

private:
    HMODULE         m_hMapiDll;
    LPMAPILOGON     m_lpfnMapiLogon;
    LPMAPILOGOFF    m_lpfnMapiLogoff;
    LPMAPISENDMAIL  m_lpfnMapiSendMail;
};

#endif
<|endoftext|>


<commit_before>#include "mtao/cmdline_parser.hpp"
#include <algorithm>
#include <type_traits>
#include <stdexcept>
#include <iostream>
#include <set>
#include <iterator>
#include <cstdlib>
#include <sstream>
#include "mtao/type_utils.h"
#include "mtao/logging/logger.hpp"

using namespace mtao::logging;

namespace mtao {

    namespace clp_internal {
        void clp_inline_test(const CommandLineParser& clp) {
            {
                auto t = trace();
                t << "Arguments(" << clp.args().size() << "): ";
                int count = 0;
                for(auto&& s: clp.args()) {
                    t<< "[" <<count++ << ":{" << s << "}] ";
                }
            }

            {
                auto t  = trace();

                t << "Options(" << clp.opts().size() << "): ";
                for(auto&& opt: clp.opts()) {
                    t << "[" << opt.first <<"("
                        << clp.opt_type(opt.first) <<"):{" ;
                    t << clp.opt_str(opt.first);
                    t << "}] ";

                }
            }
        }
    }

    CommandLineParser::CommandLineParser() {
        m_opts["help"] = Option(false,"Print help");
    }

    bool CommandLineParser::parse(int argc, char * argv[]) {

        std::vector<std::string> toks(argc);
        std::copy(argv,argv+argc,toks.begin());
        //std::transform(argv,argv+argc,toks,std::bind(std::string,std::placceholders::_1));
        //TODO: do i need to check for empty strings?
        for(std::vector<std::string>::const_iterator tokit = toks.begin()+1; tokit != toks.end(); ++ tokit) {
            auto&& tok = *tokit;
            if(tok[0] == '-') {
                if(toks.size() > 1 && tok[1] == '-') {
                    parse_long_arg(tokit);
                } else {
                    parse_short_arg(tokit);
                }
            } else {
                m_args.push_back(tok);
            }
        }
#ifndef NDEBUG
        clp_internal::clp_inline_test(*this);
#endif
        if(optT<bool>("help")) {
            std::map<std::string,std::set<std::string>> aliased_values;
            for(auto&& [a,b]: m_aliases) {
                aliased_values[b].insert(a);
            }
            for(auto&& [a,_]: m_opts) {
                aliased_values[a].insert(a);
            }
            for(auto&& [oc,opt]: m_opts) {
                auto&& av = aliased_values[oc];
                std::copy(av.begin(),av.end(), std::ostream_iterator<std::string>(std::cout, ","));
                std::cout << "(" << opt_type(oc)  << "): " << opt.hint << std::endl;
            }
            return false;
        } else {
            return true;
        }
    }

    void CommandLineParser::parse_arg(std::vector<std::string>::const_iterator& it, int prefix) {
        const std::string optname = dealias(it->substr(prefix));
        if(auto argit = m_opts.find(optname); argit != m_opts.end()) {
            std::visit([&](auto& v) {
                    using T = std::decay_t<decltype(v)>;
                    if constexpr(std::is_same_v<T,bool>) {
                        v = true;
                    } else if constexpr(std::is_same_v<T,AntiBool>) {
        if(auto argit = m_opts.find(v.target_name); argit != m_opts.end()) {
        assert(std::holds_alternative<bool>(argit->second));
            argit->second = false;
        }
                    } else {
                        ++it;
                        const std::string& value = *it;
                        try {
                            if constexpr(std::is_same_v<T,int>) {
                                v = std::stoi(value);
                            } else if constexpr(std::is_same_v<T,double>) {
                                v = std::stod(value);
                            } else if constexpr(std::is_same_v<T,std::string>) {
                                v = value;
                            }
                        } catch (std::invalid_argument e) {
                            error() << "Invalid argument: " << argit->first << "("<< opt_type(argit->first) <<"): [" << value <<"]";
                        }
                    }
                    },static_cast<OptVar&>(argit->second));
        } else {
            //TODO: Throw error
            throw std::invalid_argument( "Option " + optname + " not recognized." );
        }

    }
    std::string CommandLineParser::opt_type(const std::string& optname) const {
        return std::visit([&](auto&& v) -> std::string {
                using T = std::decay_t<decltype(v)>;
                if constexpr(std::is_same_v<T,std::string>) {
                return "string";
                } else {
                return  types::getTypeName<T>();
                }
                }, opt(optname));
    }

    void CommandLineParser::add_option(const std::string& optname, const OptVar& opt, const std::string& hint) {
        if(hint.empty()) {
            debug() << "Adding option: " << optname;
        } else {
            debug() << "Adding option: " << optname << ": " << hint;
        }
        if(auto it = m_opts.find(optname); it == m_opts.end()) {
            m_opts[optname] = Option(opt,hint);

            std::visit([&](auto&& v) {
                    using T = std::decay_t<decltype(v)>;
                    if constexpr (std::is_same_v<T,bool>) {
                    add_option(std::string("no-")+optname,AntiBool{optname},hint.empty()?("No " + hint):"");
                    }
                    },opt);
        }
    }
    void CommandLineParser::add_alias(const std::string& name_raw, const std::string& alias) {
        std::string name = dealias(name_raw);
        m_aliases[alias] = name;
    }
    void CommandLineParser::set_option(const std::string& optname, const OptVar& opt) {

        if(auto it = m_opts.find(optname); it != m_opts.end()) {
            it->second.OptVar::operator=(opt);
        } else {
            add_option(optname,opt);
        }
    }

    std::string CommandLineParser::dealias(const std::string& str) const {
        if(auto it = m_aliases.find(str); it != m_aliases.end()) {
            return it->second;
        } else {
            return str;
        }
    }

    auto CommandLineParser::opt(const std::string& optname_raw) const -> const OptVar & {
        std::string optname = dealias(optname_raw);
        if(auto argit = m_opts.find(optname); argit == m_opts.end()) {
            throw std::invalid_argument( "Option " + optname + " not recognized." );
        } else {
            return argit->second;
        }
    }
    std::string CommandLineParser::opt_str(const std::string& optname) const {
        return std::visit([&](auto&& v) -> std::string {
                using T = std::decay_t<decltype(v)>;
                if constexpr (std::is_same_v<T,bool>) {
                return v?"true":"false";
                } else if constexpr(std::is_same_v<T,AntiBool>) {
                auto bopt = opt(v.target_name);
                assert(std::holds_alternative<bool>(bopt));
                bool val = std::get<bool>(bopt);
                return v.target_name + ((val)?"=true":"=false");
                } else {
                std::stringstream ss;
                ss << v;
                return ss.str();
                }
                }, opt(optname));
    }
}
<commit_msg>undoing some win thing<commit_after>#include "mtao/cmdline_parser.hpp"
#include <algorithm>
#include <type_traits>
#include <stdexcept>
#include <iostream>
#include <set>
#include <iterator>
#include <cstdlib>
#include <sstream>
#include "mtao/type_utils.h"
#include "mtao/logging/logger.hpp"

using namespace mtao::logging;

namespace mtao {

    namespace clp_internal {
        void clp_inline_test(const CommandLineParser& clp) {
            {
                auto t = trace();
                t << "Arguments(" << clp.args().size() << "): ";
                int count = 0;
                for(auto&& s: clp.args()) {
                    t<< "[" <<count++ << ":{" << s << "}] ";
                }
            }

            {
                auto t  = trace();

                t << "Options(" << clp.opts().size() << "): ";
                for(auto&& opt: clp.opts()) {
                    t << "[" << opt.first <<"("
                        << clp.opt_type(opt.first) <<"):{" ;
                    t << clp.opt_str(opt.first);
                    t << "}] ";

                }
            }
        }
    }

    CommandLineParser::CommandLineParser() {
        m_opts["help"] = Option(false,"Print help");
    }

    bool CommandLineParser::parse(int argc, char * argv[]) {

        std::vector<std::string> toks(argc);
        std::copy(argv,argv+argc,toks.begin());
        //std::transform(argv,argv+argc,toks,std::bind(std::string,std::placceholders::_1));
        //TODO: do i need to check for empty strings?
        for(std::vector<std::string>::const_iterator tokit = toks.begin()+1; tokit != toks.end(); ++ tokit) {
            auto&& tok = *tokit;
            if(tok[0] == '-') {
                if(toks.size() > 1 && tok[1] == '-') {
                    parse_long_arg(tokit);
                } else {
                    parse_short_arg(tokit);
                }
            } else {
                m_args.push_back(tok);
            }
        }
#ifndef NDEBUG
        clp_internal::clp_inline_test(*this);
#endif
        if(optT<bool>("help")) {
            std::map<std::string,std::set<std::string>> aliased_values;
            for(auto&& [a,b]: m_aliases) {
                aliased_values[b].insert(a);
            }
            for(auto&& [a,_]: m_opts) {
                aliased_values[a].insert(a);
            }
            for(auto&& [oc,opt]: m_opts) {
                auto&& av = aliased_values[oc];
                std::copy(av.begin(),av.end(), std::ostream_iterator<std::string>(std::cout, ","));
                std::cout << "(" << opt_type(oc)  << "): " << opt.hint << std::endl;
            }
            return false;
        } else {
            return true;
        }
    }

    void CommandLineParser::parse_arg(std::vector<std::string>::const_iterator& it, int prefix) {
        const std::string optname = dealias(it->substr(prefix));
        if(auto argit = m_opts.find(optname); argit != m_opts.end()) {
            std::visit([&](auto& v) {
                    using T = std::decay_t<decltype(v)>;
                    if constexpr(std::is_same_v<T,bool>) {
                        v = true;
                    } else if constexpr(std::is_same_v<T,AntiBool>) {
        if(auto argit = m_opts.find(v.target_name); argit != m_opts.end()) {
        assert(std::holds_alternative<bool>(argit->second));
            argit->second = false;
        }
                    } else {
                        ++it;
                        const std::string& value = *it;
                        try {
                            if constexpr(std::is_same_v<T,int>) {
                                v = std::stoi(value);
                            } else if constexpr(std::is_same_v<T,double>) {
                                v = std::stod(value);
                            } else if constexpr(std::is_same_v<T,std::string>) {
                                v = value;
                            }
                        } catch (const std::invalid_argument& e) {
                            error() << "Invalid argument: " << argit->first << "("<< opt_type(argit->first) <<"): [" << value <<"]";
                        }
                    }
                    },static_cast<OptVar&>(argit->second));
        } else {
            //TODO: Throw error
            throw std::invalid_argument( "Option " + optname + " not recognized." );
        }

    }
    std::string CommandLineParser::opt_type(const std::string& optname) const {
        return std::visit([&](auto&& v) -> std::string {
                using T = std::decay_t<decltype(v)>;
                if constexpr(std::is_same_v<T,std::string>) {
                return "string";
                } else {
                return  types::getTypeName<T>();
                }
                }, opt(optname));
    }

    void CommandLineParser::add_option(const std::string& optname, const OptVar& opt, const std::string& hint) {
        if(hint.empty()) {
            debug() << "Adding option: " << optname;
        } else {
            debug() << "Adding option: " << optname << ": " << hint;
        }
        if(auto it = m_opts.find(optname); it == m_opts.end()) {
            m_opts[optname] = Option(opt,hint);

            std::visit([&](auto&& v) {
                    using T = std::decay_t<decltype(v)>;
                    if constexpr (std::is_same_v<T,bool>) {
                    add_option(std::string("no-")+optname,AntiBool{optname},hint.empty()?("No " + hint):"");
                    }
                    },opt);
        }
    }
    void CommandLineParser::add_alias(const std::string& name_raw, const std::string& alias) {
        std::string name = dealias(name_raw);
        m_aliases[alias] = name;
    }
    void CommandLineParser::set_option(const std::string& optname, const OptVar& opt) {

        if(auto it = m_opts.find(optname); it != m_opts.end()) {
            it->second.OptVar::operator=(opt);
        } else {
            add_option(optname,opt);
        }
    }

    std::string CommandLineParser::dealias(const std::string& str) const {
        if(auto it = m_aliases.find(str); it != m_aliases.end()) {
            return it->second;
        } else {
            return str;
        }
    }

    auto CommandLineParser::opt(const std::string& optname_raw) const -> const OptVar & {
        std::string optname = dealias(optname_raw);
        if(auto argit = m_opts.find(optname); argit == m_opts.end()) {
            throw std::invalid_argument( "Option " + optname + " not recognized." );
        } else {
            return argit->second;
        }
    }
    std::string CommandLineParser::opt_str(const std::string& optname) const {
        return std::visit([&](auto&& v) -> std::string {
                using T = std::decay_t<decltype(v)>;
                if constexpr (std::is_same_v<T,bool>) {
                return v?"true":"false";
                } else if constexpr(std::is_same_v<T,AntiBool>) {
                auto bopt = opt(v.target_name);
                assert(std::holds_alternative<bool>(bopt));
                bool val = std::get<bool>(bopt);
                return v.target_name + ((val)?"=true":"=false");
                } else {
                std::stringstream ss;
                ss << v;
                return ss.str();
                }
                }, opt(optname));
    }
}
<|endoftext|>


<commit_before>/* Copyright 2013-present Barefoot Networks, Inc.
 *
 * 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.
 */

#include <bm/bm_sim/pcap_file.h>
#include <bm/bm_sim/logger.h>

#include <cassert>
#include <chrono>
#include <thread>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include <cstring>

namespace bm {

namespace {

// TODO(antonin): remove or good enough?
void pcap_fatal_error(const std::string &message) {
  Logger::get()->critical(message);
  exit(1);
}

}  // namespace

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

// This method should be in some separate C library
// Converts a timeval into a string.
// static
std::string
PcapPacket::timevalToString(const struct timeval *tv) {
  std::stringstream result;
  result << std::to_string(tv->tv_sec) << ":"
         << std::setfill('0') << std::setw(6) << std::to_string(tv->tv_usec);
  return result.str();
}

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

PcapFileBase::PcapFileBase(unsigned port, std::string filename)
  : port(port),
    filename(filename) {}

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

// A stream-like abstraction of a PCAP (Packet capture) file.
PcapFileIn::PcapFileIn(unsigned port, std::string filename)
  : PcapFileBase(port, filename),
    pcap(nullptr),
    current_header(nullptr),
    current_data(nullptr) {
  reset();
}

void
PcapFileIn::deallocate() {
  if (pcap != nullptr)
    pcap_close(pcap);
  pcap = nullptr;
  current_header = nullptr;
  current_data = nullptr;
}

PcapFileIn::~PcapFileIn() {
  deallocate();
}

void
PcapFileIn::open() {
  char errbuf[PCAP_ERRBUF_SIZE];

  pcap = pcap_open_offline(filename.c_str(), errbuf);
  if (pcap == nullptr)
    pcap_fatal_error(errbuf);
  state = State::Opened;
}

void
PcapFileIn::reset() {
  deallocate();
  state = State::Uninitialized;
  open();
}

bool
PcapFileIn::moveNext() {
  switch (state) {
    case State::AtEnd:
      return false;
    case State::Opened:
    case State::Reading:
      return advance();
    case State::Uninitialized:
    default:
      pcap_fatal_error("Unexpected state");
      return false;  // unreachable
  }
}

bool
PcapFileIn::advance() {
  int pcap_status = pcap_next_ex(pcap, &current_header, &current_data);
  if (pcap_status == 1) {  // packet read without problems
    if (current_header->caplen != current_header->len) {
      pcap_fatal_error(
          std::string("Incompletely captured packet in ") + filename);
    }
    state = State::Reading;
    return true;
  } else if (pcap_status == -2) {  // end of file
    state = State::AtEnd;
    return false;
  } else if (pcap_status == -1) {
    pcap_fatal_error(
        std::string("Error while reading packet from ") + filename);
  } else {
    // other status impossible, even 0 (which is only for live capture)
    assert(0 && "Invalid pcap status");
  }
  // unreachable
  return false;
}

std::unique_ptr<PcapPacket>
PcapFileIn::current() const {
  switch (state) {
  case State::Reading:
    {
      PcapPacket *packet = new PcapPacket(port, current_data, current_header);
      return std::unique_ptr<PcapPacket>(packet);
    }
  case State::Opened:
    pcap_fatal_error("Must call moveNext() before calling current()");
    break;
  case State::AtEnd:
    pcap_fatal_error("Cannot read past end-of-file");
    break;
  case State::Uninitialized:
    /* fallthrough */
  default:
    pcap_fatal_error("Unexpected state");
  }
  return nullptr;  // unreachable
}

bool PcapFileIn::atEOF() const {
  return state == State::AtEnd;
}

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

PcapFilesReader::PcapFilesReader(bool respectTiming,
                                 unsigned wait_time_in_seconds)
  : nonEmptyFiles(0),
    wait_time_in_seconds(wait_time_in_seconds),
    respectTiming(respectTiming),
    started(false) {
  timerclear(&zero);
}

void
PcapFilesReader::addFile(unsigned index, std::string file) {
  auto f = std::unique_ptr<PcapFileIn>(new PcapFileIn(index, file));
  files.push_back(std::move(f));
}

void
PcapFilesReader::scan() {
  while (true) {
    if (nonEmptyFiles == 0) {
      BMLOG_DEBUG("Pcap reader: end of all input files");
      // notifyAllEnd();
      return;
    }

    int earliest_index = -1;
    const struct timeval *earliest_time;

    for (unsigned i=0; i < files.size(); i++) {
      auto file = files.at(i).get();
      if (file->atEOF()) continue;

      std::unique_ptr<PcapPacket> p = file->current();
      if (earliest_index == -1) {
        earliest_index = i;
        earliest_time = p->getTime();
      } else {
        const struct timeval *time = p->getTime();
        if (timercmp(time, earliest_time, <)) {
          earliest_index = i;
          earliest_time = time;
        }
      }
    }

    assert(earliest_index >= 0);
    struct timeval delay;

    BMLOG_DEBUG("Pcap reader: first packet to send {}",
                PcapPacket::timevalToString(earliest_time));

    if (respectTiming) {
      struct timeval delta;
      timersub(earliest_time, &firstPacketTime, &delta);

      struct timeval now;
      gettimeofday(&now, nullptr);

      struct timeval elapsed;
      timersub(&now, &startTime, &elapsed);

      timersub(&delta, &elapsed, &delay);
      BMLOG_DEBUG("Pcap reader: delta {}, elapsed {}, delay {}",
                  PcapPacket::timevalToString(&delta),
                  PcapPacket::timevalToString(&elapsed),
                  PcapPacket::timevalToString(&delay));
    } else {
      timerclear(&delay);
    }

    schedulePacket((unsigned)earliest_index, &delay);
  }
}

void PcapFilesReader::timerFired() {
  auto file = files.at(scheduledIndex).get();
  std::unique_ptr<PcapPacket> packet = file->current();

  if (handler != nullptr)
    handler(packet->getPort(), packet->getData(), packet->getLength(), cookie);
  else
    pcap_fatal_error("No packet handler set when sending packet");

  bool success = file->moveNext();
  if (!success)
    nonEmptyFiles--;
}

void PcapFilesReader::schedulePacket(unsigned index, const struct timeval *at) {
  scheduledIndex = index;

  int compare = timercmp(at, &zero, <=);
  if (compare) {
    // packet should already have been sent
    timerFired();
  } else {
    auto duration = std::chrono::seconds(at->tv_sec) +
      std::chrono::microseconds(at->tv_usec);
    BMLOG_DEBUG("Pcap reader: sleep for {}", duration.count());
    std::this_thread::sleep_for(duration);
    timerFired();
  }
}

void PcapFilesReader::start() {
  BMLOG_DEBUG("Pcap reader: starting PcapFilesReader {}",
              std::to_string(files.size()));

  // Give the switch some time to initialize
  if (wait_time_in_seconds > 0) {
    BMLOG_DEBUG("Pcap reader: waiting for {} seconds",
                std::to_string(wait_time_in_seconds));
    auto duration = std::chrono::seconds(wait_time_in_seconds);
    std::this_thread::sleep_for(duration);
  }

  // Find out time of first packet
  const struct timeval *firstTime = nullptr;

  // Linear scan; we could use a priority queue, but probably this
  // is more efficient for a small number of files.
  for (auto &file : files) {
    bool success = file->moveNext();
    if (success) {
      nonEmptyFiles++;

      std::unique_ptr<PcapPacket> p = file->current();
      const struct timeval *ptime = p->getTime();
      if (firstTime == nullptr)
        firstTime = ptime;
      else if (timercmp(ptime, firstTime, <))
        firstTime = ptime;
    }
  }

  if (nonEmptyFiles > 0) {
    assert(firstTime != nullptr);
    firstPacketTime = *firstTime;
    BMLOG_DEBUG("Pcap reader: first packet time {}",
                PcapPacket::timevalToString(firstTime));
  }

  if (started)
    pcap_fatal_error("Reader already started");

  started = true;
  gettimeofday(&startTime, nullptr);
  scan();
}

PacketDispatcherIface::ReturnCode
PcapFilesReader::set_packet_handler(const PacketHandler &hnd, void *ck) {
  assert(hnd);
  assert(ck);

  handler = hnd;
  cookie = ck;
  return ReturnCode::SUCCESS;
}

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

PcapFileOut::PcapFileOut(unsigned port, std::string filename)
  : PcapFileBase(port, filename) {
  pcap = pcap_open_dead(0, 0);
  if (pcap == nullptr)
    pcap_fatal_error(
      std::string("Could not open file ") + filename + " for writing");
  dumper = pcap_dump_open(pcap, filename.c_str());
  if (dumper == nullptr)
    pcap_fatal_error(
      std::string("Could not open file ") + filename + " for writing");
}

void
PcapFileOut::writePacket(const char *data, unsigned length) {
  struct pcap_pkthdr pkt_header;
  memset(&pkt_header, 0, sizeof(pkt_header));
  gettimeofday(&pkt_header.ts, NULL);
  pkt_header.caplen = length;
  pkt_header.len = length;
  pcap_dump(reinterpret_cast<unsigned char *>(dumper), &pkt_header,
            reinterpret_cast<const unsigned char *>(data));
  pcap_dump_flush(dumper);
}

PcapFileOut::~PcapFileOut() {
  pcap_dump_close(dumper);
  pcap_close(pcap);
}

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

PcapFilesWriter::PcapFilesWriter() {}

void
PcapFilesWriter::addFile(unsigned port, std::string file) {
  auto f = std::unique_ptr<PcapFileOut>(new PcapFileOut(port, file));
  files.emplace(port, std::move(f));
}

void
PcapFilesWriter::send_packet(int port_num, const char *buffer, int len) {
  unsigned idx = port_num;

  if (files.find(port_num) == files.end())
    // The behavior of the bmi_* library seems to be to ignore
    // packets sent to inexistent interfaces, so we replicate it here.
    return;

  auto file = files.at(idx).get();
  file->writePacket(buffer, len);
}

}  // namespace bm
<commit_msg>Fix maybe uninitialized warning in src/bm_sim/pcap_file.cpp<commit_after>/* Copyright 2013-present Barefoot Networks, Inc.
 *
 * 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.
 */

#include <bm/bm_sim/pcap_file.h>
#include <bm/bm_sim/logger.h>

#include <cassert>
#include <chrono>
#include <thread>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

#include <cstring>

namespace bm {

namespace {

// TODO(antonin): remove or good enough?
void pcap_fatal_error(const std::string &message) {
  Logger::get()->critical(message);
  exit(1);
}

}  // namespace

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

// This method should be in some separate C library
// Converts a timeval into a string.
// static
std::string
PcapPacket::timevalToString(const struct timeval *tv) {
  std::stringstream result;
  result << std::to_string(tv->tv_sec) << ":"
         << std::setfill('0') << std::setw(6) << std::to_string(tv->tv_usec);
  return result.str();
}

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

PcapFileBase::PcapFileBase(unsigned port, std::string filename)
  : port(port),
    filename(filename) {}

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

// A stream-like abstraction of a PCAP (Packet capture) file.
PcapFileIn::PcapFileIn(unsigned port, std::string filename)
  : PcapFileBase(port, filename),
    pcap(nullptr),
    current_header(nullptr),
    current_data(nullptr) {
  reset();
}

void
PcapFileIn::deallocate() {
  if (pcap != nullptr)
    pcap_close(pcap);
  pcap = nullptr;
  current_header = nullptr;
  current_data = nullptr;
}

PcapFileIn::~PcapFileIn() {
  deallocate();
}

void
PcapFileIn::open() {
  char errbuf[PCAP_ERRBUF_SIZE];

  pcap = pcap_open_offline(filename.c_str(), errbuf);
  if (pcap == nullptr)
    pcap_fatal_error(errbuf);
  state = State::Opened;
}

void
PcapFileIn::reset() {
  deallocate();
  state = State::Uninitialized;
  open();
}

bool
PcapFileIn::moveNext() {
  switch (state) {
    case State::AtEnd:
      return false;
    case State::Opened:
    case State::Reading:
      return advance();
    case State::Uninitialized:
    default:
      pcap_fatal_error("Unexpected state");
      return false;  // unreachable
  }
}

bool
PcapFileIn::advance() {
  int pcap_status = pcap_next_ex(pcap, &current_header, &current_data);
  if (pcap_status == 1) {  // packet read without problems
    if (current_header->caplen != current_header->len) {
      pcap_fatal_error(
          std::string("Incompletely captured packet in ") + filename);
    }
    state = State::Reading;
    return true;
  } else if (pcap_status == -2) {  // end of file
    state = State::AtEnd;
    return false;
  } else if (pcap_status == -1) {
    pcap_fatal_error(
        std::string("Error while reading packet from ") + filename);
  } else {
    // other status impossible, even 0 (which is only for live capture)
    assert(0 && "Invalid pcap status");
  }
  // unreachable
  return false;
}

std::unique_ptr<PcapPacket>
PcapFileIn::current() const {
  switch (state) {
  case State::Reading:
    {
      PcapPacket *packet = new PcapPacket(port, current_data, current_header);
      return std::unique_ptr<PcapPacket>(packet);
    }
  case State::Opened:
    pcap_fatal_error("Must call moveNext() before calling current()");
    break;
  case State::AtEnd:
    pcap_fatal_error("Cannot read past end-of-file");
    break;
  case State::Uninitialized:
    /* fallthrough */
  default:
    pcap_fatal_error("Unexpected state");
  }
  return nullptr;  // unreachable
}

bool PcapFileIn::atEOF() const {
  return state == State::AtEnd;
}

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

PcapFilesReader::PcapFilesReader(bool respectTiming,
                                 unsigned wait_time_in_seconds)
  : nonEmptyFiles(0),
    wait_time_in_seconds(wait_time_in_seconds),
    respectTiming(respectTiming),
    started(false) {
  timerclear(&zero);
}

void
PcapFilesReader::addFile(unsigned index, std::string file) {
  auto f = std::unique_ptr<PcapFileIn>(new PcapFileIn(index, file));
  files.push_back(std::move(f));
}

void
PcapFilesReader::scan() {
  while (true) {
    if (nonEmptyFiles == 0) {
      BMLOG_DEBUG("Pcap reader: end of all input files");
      // notifyAllEnd();
      return;
    }

    int earliest_index = -1;
    const struct timeval *earliest_time = nullptr;

    for (unsigned int i = 0; i < files.size(); i++) {
      auto file = files.at(i).get();
      if (file->atEOF()) continue;

      std::unique_ptr<PcapPacket> p = file->current();
      if (earliest_index == -1) {
        earliest_index = i;
        earliest_time = p->getTime();
      } else {
        const struct timeval *time = p->getTime();
        if (timercmp(time, earliest_time, <)) {
          earliest_index = i;
          earliest_time = time;
        }
      }
    }

    assert(earliest_index >= 0 && earliest_time != nullptr);
    struct timeval delay;

    BMLOG_DEBUG("Pcap reader: first packet to send {}",
                PcapPacket::timevalToString(earliest_time));

    if (respectTiming) {
      struct timeval delta;
      timersub(earliest_time, &firstPacketTime, &delta);

      struct timeval now;
      gettimeofday(&now, nullptr);

      struct timeval elapsed;
      timersub(&now, &startTime, &elapsed);

      timersub(&delta, &elapsed, &delay);
      BMLOG_DEBUG("Pcap reader: delta {}, elapsed {}, delay {}",
                  PcapPacket::timevalToString(&delta),
                  PcapPacket::timevalToString(&elapsed),
                  PcapPacket::timevalToString(&delay));
    } else {
      timerclear(&delay);
    }

    schedulePacket((unsigned)earliest_index, &delay);
  }
}

void PcapFilesReader::timerFired() {
  auto file = files.at(scheduledIndex).get();
  std::unique_ptr<PcapPacket> packet = file->current();

  if (handler != nullptr)
    handler(packet->getPort(), packet->getData(), packet->getLength(), cookie);
  else
    pcap_fatal_error("No packet handler set when sending packet");

  bool success = file->moveNext();
  if (!success)
    nonEmptyFiles--;
}

void PcapFilesReader::schedulePacket(unsigned index, const struct timeval *at) {
  scheduledIndex = index;

  int compare = timercmp(at, &zero, <=);
  if (compare) {
    // packet should already have been sent
    timerFired();
  } else {
    auto duration = std::chrono::seconds(at->tv_sec) +
      std::chrono::microseconds(at->tv_usec);
    BMLOG_DEBUG("Pcap reader: sleep for {}", duration.count());
    std::this_thread::sleep_for(duration);
    timerFired();
  }
}

void PcapFilesReader::start() {
  BMLOG_DEBUG("Pcap reader: starting PcapFilesReader {}",
              std::to_string(files.size()));

  // Give the switch some time to initialize
  if (wait_time_in_seconds > 0) {
    BMLOG_DEBUG("Pcap reader: waiting for {} seconds",
                std::to_string(wait_time_in_seconds));
    auto duration = std::chrono::seconds(wait_time_in_seconds);
    std::this_thread::sleep_for(duration);
  }

  // Find out time of first packet
  const struct timeval *firstTime = nullptr;

  // Linear scan; we could use a priority queue, but probably this
  // is more efficient for a small number of files.
  for (auto &file : files) {
    bool success = file->moveNext();
    if (success) {
      nonEmptyFiles++;

      std::unique_ptr<PcapPacket> p = file->current();
      const struct timeval *ptime = p->getTime();
      if (firstTime == nullptr)
        firstTime = ptime;
      else if (timercmp(ptime, firstTime, <))
        firstTime = ptime;
    }
  }

  if (nonEmptyFiles > 0) {
    assert(firstTime != nullptr);
    firstPacketTime = *firstTime;
    BMLOG_DEBUG("Pcap reader: first packet time {}",
                PcapPacket::timevalToString(firstTime));
  }

  if (started)
    pcap_fatal_error("Reader already started");

  started = true;
  gettimeofday(&startTime, nullptr);
  scan();
}

PacketDispatcherIface::ReturnCode
PcapFilesReader::set_packet_handler(const PacketHandler &hnd, void *ck) {
  assert(hnd);
  assert(ck);

  handler = hnd;
  cookie = ck;
  return ReturnCode::SUCCESS;
}

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

PcapFileOut::PcapFileOut(unsigned port, std::string filename)
  : PcapFileBase(port, filename) {
  pcap = pcap_open_dead(0, 0);
  if (pcap == nullptr)
    pcap_fatal_error(
      std::string("Could not open file ") + filename + " for writing");
  dumper = pcap_dump_open(pcap, filename.c_str());
  if (dumper == nullptr)
    pcap_fatal_error(
      std::string("Could not open file ") + filename + " for writing");
}

void
PcapFileOut::writePacket(const char *data, unsigned length) {
  struct pcap_pkthdr pkt_header;
  memset(&pkt_header, 0, sizeof(pkt_header));
  gettimeofday(&pkt_header.ts, NULL);
  pkt_header.caplen = length;
  pkt_header.len = length;
  pcap_dump(reinterpret_cast<unsigned char *>(dumper), &pkt_header,
            reinterpret_cast<const unsigned char *>(data));
  pcap_dump_flush(dumper);
}

PcapFileOut::~PcapFileOut() {
  pcap_dump_close(dumper);
  pcap_close(pcap);
}

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

PcapFilesWriter::PcapFilesWriter() {}

void
PcapFilesWriter::addFile(unsigned port, std::string file) {
  auto f = std::unique_ptr<PcapFileOut>(new PcapFileOut(port, file));
  files.emplace(port, std::move(f));
}

void
PcapFilesWriter::send_packet(int port_num, const char *buffer, int len) {
  unsigned idx = port_num;

  if (files.find(port_num) == files.end())
    // The behavior of the bmi_* library seems to be to ignore
    // packets sent to inexistent interfaces, so we replicate it here.
    return;

  auto file = files.at(idx).get();
  file->writePacket(buffer, len);
}

}  // namespace bm
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "ordering.h"

// appleseed.foundation headers.
#include "foundation/core/exceptions/exceptionnotimplemented.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"

// Standard headers.
#include <algorithm>
#include <cassert>

using namespace foundation;
using namespace std;

namespace foundation
{

//
// 2D ordering generators implementation.
//

void linear_ordering(
    vector<size_t>&     ordering,
    const size_t        size)
{
    for (size_t i = 0; i < size; ++i)
        ordering.push_back(i);
}

void spiral_ordering(
    vector<size_t>&     ordering,
    const size_t        size_x,
    const size_t        size_y)
{
    throw ExceptionNotImplemented();
}

namespace
{
    void hilbert(
        vector<size_t>& ordering,
        const int       size_x,
        const int       size_y,
        Vector2i        point,
        int             size,
        const Vector2i& dx,
        const Vector2i& dy)
    {
        if (size > 1)
        {
            // Recursively visit all four sub quads.
            size >>= 1;
            hilbert(ordering, size_x, size_y, point, size, dy, dx);
            point += dy * size;
            hilbert(ordering, size_x, size_y, point, size, dx, dy);
            point += dx * size;
            hilbert(ordering, size_x, size_y, point, size, dx, dy);
            point += dx * (size - 1) - dy;
            hilbert(ordering, size_x, size_y, point, size, -dy, -dx);
        }
        else
        {
            // Insert this tile into the tile array if it's inside the boundaries of the frame.
            assert(size == 1);
            assert(point.x >= 0);
            assert(point.y >= 0);
            if (point.x < size_x && point.y < size_y)
                ordering.push_back(size_t(point.y * size_x + point.x));
        }
    }
}

void hilbert_ordering(
    vector<size_t>&     ordering,
    const size_t        size_x,
    const size_t        size_y)
{
    // This Hilbert curve generator only works on a square grid whose size is a power of two.
    const size_t root_size = next_pow2(max(size_x, size_y));

    hilbert(
        ordering,
        static_cast<int>(size_x),
        static_cast<int>(size_y),
        Vector2i(0, 0),
        static_cast<int>(root_size),
        Vector2i(1, 0),
        Vector2i(0, 1));
}

}   // namespace foundation
<commit_msg>fixed compilation error in standalone appleseed.foundation.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "ordering.h"

// appleseed.foundation headers.
#include "foundation/core/exceptions/exceptionnotimplemented.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"

// Standard headers.
#include <algorithm>
#include <cassert>

using namespace foundation;
using namespace std;

namespace foundation
{

//
// 2D ordering generators implementation.
//

void linear_ordering(
    vector<size_t>&     ordering,
    const size_t        size)
{
    for (size_t i = 0; i < size; ++i)
        ordering.push_back(i);
}

void spiral_ordering(
    vector<size_t>&     ordering,
    const size_t        size_x,
    const size_t        size_y)
{
    throw ExceptionNotImplemented();
}

namespace
{
    void hilbert(
        vector<size_t>& ordering,
        const int       size_x,
        const int       size_y,
        Vector2i        point,
        int             size,
        const Vector2i& dx,
        const Vector2i& dy)
    {
        if (size > 1)
        {
            // Recursively visit all four sub quads.
            size >>= 1;
            hilbert(ordering, size_x, size_y, point, size, dy, dx);
            point += dy * size;
            hilbert(ordering, size_x, size_y, point, size, dx, dy);
            point += dx * size;
            hilbert(ordering, size_x, size_y, point, size, dx, dy);
            point += dx * (size - 1) - dy;
            hilbert(ordering, size_x, size_y, point, size, -dy, -dx);
        }
        else
        {
            // Insert this tile into the tile array if it's inside the boundaries of the frame.
            assert(size == 1);
            assert(point.x >= 0);
            assert(point.y >= 0);
            if (point.x < size_x && point.y < size_y)
                ordering.push_back(size_t(point.y * size_x + point.x));
        }
    }
}

void hilbert_ordering(
    vector<size_t>&     ordering,
    const size_t        size_x,
    const size_t        size_y)
{
    // This Hilbert curve generator only works on a square grid whose size is a power of two.
    const size_t root_size = next_pow2(std::max(size_x, size_y));   // needs full qualification

    hilbert(
        ordering,
        static_cast<int>(size_x),
        static_cast<int>(size_y),
        Vector2i(0, 0),
        static_cast<int>(root_size),
        Vector2i(1, 0),
        Vector2i(0, 1));
}

}   // namespace foundation
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "AprioriFilter.h"
#include "TestDataSets.h"

#include <iostream>
#include <string>

using namespace std;

// aExpected is itemsets, space delimted, and item inside the set ',' delimited.
bool CheckSet(string aExpected, set<ItemSet> aObserved) {
  vector<string> itemsets;
  Tokenize(aExpected, itemsets, " ");

  ASSERT(itemsets.size() == aObserved.size());
  if (itemsets.size() != aObserved.size()) {
    return false;
  }

  set<ItemSet>::const_iterator itr = aObserved.begin();
  set<ItemSet>::const_iterator end = aObserved.end();
  int i = 0;
  for (; itr != end; itr++, i++) {
    vector<string> items;
    Tokenize(itemsets[i], items, ",");
    ItemSet item1;
    for (unsigned i = 0; i < items.size(); i++) {
      item1 += Item(items[i]);
    }
    ItemSet item2(*itr);
    ASSERT(item1 == item2);
    if (!(item1 == item2)) {
      return false;
    }
  }
  return true;
}

extern set<ItemSet>
GenerateCandidates(const set<ItemSet>& aCandidates,
                   int aItemSetSize,
                   shared_ptr<AprioriFilter> aFilter,
                   int numThreads);

extern set<ItemSet>
GenerateInitialCandidates(const InvertedDataSetIndex& aIndex,
                          shared_ptr<AprioriFilter> aFilter);

extern bool ContainsAllSubSets(const set<ItemSet>& aContainer,
                               const ItemSet& aItemSet);

TEST(Apriori_Test, main) {
  Item::SetCompareMode(Item::ALPHABETIC_COMPARE);
  Item::ResetBaseId();

  {
    InvertedDataSetIndex index(Test3DataSet());
    ASSERT_TRUE(index.Load());
    ASSERT_TRUE(index.GetNumItems() == 20);

    // Test GenerateInitialCandidates().
    {
      shared_ptr<AprioriFilter> msf = make_shared<MinSupportFilter>(0.6, index);
      set<ItemSet> candidates = GenerateInitialCandidates(index, msf);
      ASSERT_TRUE(CheckSet("a s u", candidates));
    }
    {
      shared_ptr<AprioriFilter> msf = make_shared<MinSupportFilter>(0.3, index);
      set<ItemSet> candidates = GenerateInitialCandidates(index, msf);
      // Candidates are: {a,c,d,e,f,g,r,s,t,u,w,y}
      CheckSet("a c d e f g r s t u w y", candidates);
    }

    // Test bool ContainsAllSubSets(const set<ItemSet> &aContainer, const ItemSet &aItemSet)
    {
      set<ItemSet> container;
      container.insert(ItemSet("a", "b"));
      container.insert(ItemSet("a", "c"));
      container.insert(ItemSet("b", "c"));

      ItemSet abc("a", "b", "c");
      ASSERT_TRUE(ContainsAllSubSets(container, abc));
    }
    // Test GenerateCandidates()...
    {
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "3"), ItemSet("1", "2", "4")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "4"), ItemSet("1", "3", "4")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "3", "4"), ItemSet("1", "3", "5")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "3"), ItemSet("2", "3", "4")) == 2);

      set<ItemSet> P;
      P.insert(ItemSet("1", "2", "3"));
      P.insert(ItemSet("1", "2", "4"));
      P.insert(ItemSet("1", "3", "4"));
      P.insert(ItemSet("1", "3", "5"));
      P.insert(ItemSet("2", "3", "4"));

      shared_ptr<AprioriFilter> F = make_shared<AlwaysAcceptFilter>();
      set<ItemSet> R = GenerateCandidates(P, 4, F, 1);

      ASSERT_TRUE(R.size() == 1);
      ASSERT_TRUE(*R.begin() == ItemSet("1", "2", "3", "4"));
    }
  }
  {
    // Test a simulation of Apriori, with the data set given by Agrual's paper.
    InvertedDataSetIndex index(Test4DataSet());
    ASSERT_TRUE(index.Load());

    /*
      Data set:
      1 3 4
      2 3 5
      1 2 3 5
      2 5

      Initial candidates / Support
      1/2
      2/3
      3/3
      5/3
    */
    int c = 0;
    ASSERT_TRUE((c = index.Count(ItemSet("1"))) == 2);
    ASSERT_TRUE((c = index.Count(ItemSet("2"))) == 3);
    ASSERT_TRUE((c = index.Count(ItemSet("3"))) == 3);
    ASSERT_TRUE((c = index.Count(ItemSet("5"))) == 3);

    shared_ptr<AprioriFilter> filter = make_shared<MinCountFilter>(2, index);
    set<ItemSet> initialCandidates = GenerateInitialCandidates(index, filter);
    ASSERT_TRUE(CheckSet("1 2 3 5", initialCandidates));

    // Test next generation...
    set<ItemSet> candidates = GenerateCandidates(initialCandidates, 2, filter, 1);
    ASSERT_TRUE(CheckSet("1,3 2,3 2,5 3,5", candidates));

    candidates = GenerateCandidates(candidates, 3, filter, 1);
    ASSERT_TRUE(CheckSet("2,3,5", candidates));

  }
}

extern int MinAbsSup(int A, int B, int N, double E);

TEST(MinAbsSupFilter, main) {
  EXPECT_EQ(MinAbsSup(250, 250, 1000, 0.999), 81);
  EXPECT_EQ(MinAbsSup(250, 500, 1000, 0.999), 146);
  EXPECT_EQ(MinAbsSup(600, 500, 1000, 0.999), 324);
  EXPECT_EQ(MinAbsSup(500, 500, 1000, 0.999), 274);
  EXPECT_EQ(MinAbsSup(500, 1000, 1000, 0.999), 500);
  EXPECT_EQ(MinAbsSup(500, 1000, 10000, 0.999), 71);
  EXPECT_EQ(MinAbsSup(50, 1000, 10000, 0.999), 12);
  EXPECT_EQ(MinAbsSup(50, 5000, 10000, 0.999), 36);
}
<commit_msg>Normalize whitespace in Test_Apriori.cpp<commit_after>#include "gtest/gtest.h"
#include "AprioriFilter.h"
#include "TestDataSets.h"

#include <iostream>
#include <string>

using namespace std;

// aExpected is itemsets, space delimted, and item inside the set ',' delimited.
bool CheckSet(string aExpected, set<ItemSet> aObserved) {
  vector<string> itemsets;
  Tokenize(aExpected, itemsets, " ");

  ASSERT(itemsets.size() == aObserved.size());
  if (itemsets.size() != aObserved.size()) {
    return false;
  }

  set<ItemSet>::const_iterator itr = aObserved.begin();
  set<ItemSet>::const_iterator end = aObserved.end();
  int i = 0;
  for (; itr != end; itr++, i++) {
    vector<string> items;
    Tokenize(itemsets[i], items, ",");
    ItemSet item1;
    for (unsigned i = 0; i < items.size(); i++) {
      item1 += Item(items[i]);
    }
    ItemSet item2(*itr);
    ASSERT(item1 == item2);
    if (!(item1 == item2)) {
      return false;
    }
  }
  return true;
}

extern set<ItemSet>
GenerateCandidates(const set<ItemSet>& aCandidates,
                   int aItemSetSize,
                   shared_ptr<AprioriFilter> aFilter,
                   int numThreads);

extern set<ItemSet>
GenerateInitialCandidates(const InvertedDataSetIndex& aIndex,
                          shared_ptr<AprioriFilter> aFilter);

extern bool ContainsAllSubSets(const set<ItemSet>& aContainer,
                               const ItemSet& aItemSet);

TEST(Apriori_Test, main) {
  Item::SetCompareMode(Item::ALPHABETIC_COMPARE);
  Item::ResetBaseId();

  {
    InvertedDataSetIndex index(Test3DataSet());
    ASSERT_TRUE(index.Load());
    ASSERT_TRUE(index.GetNumItems() == 20);

    // Test GenerateInitialCandidates().
    {
      shared_ptr<AprioriFilter> msf = make_shared<MinSupportFilter>(0.6, index);
      set<ItemSet> candidates = GenerateInitialCandidates(index, msf);
      ASSERT_TRUE(CheckSet("a s u", candidates));
    }
    {
      shared_ptr<AprioriFilter> msf = make_shared<MinSupportFilter>(0.3, index);
      set<ItemSet> candidates = GenerateInitialCandidates(index, msf);
      // Candidates are: {a,c,d,e,f,g,r,s,t,u,w,y}
      CheckSet("a c d e f g r s t u w y", candidates);
    }

    // Test bool ContainsAllSubSets(const set<ItemSet> &aContainer, const ItemSet &aItemSet)
    {
      set<ItemSet> container;
      container.insert(ItemSet("a", "b"));
      container.insert(ItemSet("a", "c"));
      container.insert(ItemSet("b", "c"));

      ItemSet abc("a", "b", "c");
      ASSERT_TRUE(ContainsAllSubSets(container, abc));
    }
    // Test GenerateCandidates()...
    {
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "3"), ItemSet("1", "2", "4")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "4"), ItemSet("1", "3", "4")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "3", "4"), ItemSet("1", "3", "5")) == 2);
      ASSERT_TRUE(IntersectionSize(ItemSet("1", "2", "3"), ItemSet("2", "3", "4")) == 2);

      set<ItemSet> P;
      P.insert(ItemSet("1", "2", "3"));
      P.insert(ItemSet("1", "2", "4"));
      P.insert(ItemSet("1", "3", "4"));
      P.insert(ItemSet("1", "3", "5"));
      P.insert(ItemSet("2", "3", "4"));

      shared_ptr<AprioriFilter> F = make_shared<AlwaysAcceptFilter>();
      set<ItemSet> R = GenerateCandidates(P, 4, F, 1);

      ASSERT_TRUE(R.size() == 1);
      ASSERT_TRUE(*R.begin() == ItemSet("1", "2", "3", "4"));
    }
  }
  {
    // Test a simulation of Apriori, with the data set given by Agrual's paper.
    InvertedDataSetIndex index(Test4DataSet());
    ASSERT_TRUE(index.Load());

    /*
      Data set:
      1 3 4
      2 3 5
      1 2 3 5
      2 5

      Initial candidates / Support
      1/2
      2/3
      3/3
      5/3
    */
    int c = 0;
    ASSERT_TRUE((c = index.Count(ItemSet("1"))) == 2);
    ASSERT_TRUE((c = index.Count(ItemSet("2"))) == 3);
    ASSERT_TRUE((c = index.Count(ItemSet("3"))) == 3);
    ASSERT_TRUE((c = index.Count(ItemSet("5"))) == 3);

    shared_ptr<AprioriFilter> filter = make_shared<MinCountFilter>(2, index);
    set<ItemSet> initialCandidates = GenerateInitialCandidates(index, filter);
    ASSERT_TRUE(CheckSet("1 2 3 5", initialCandidates));

    // Test next generation...
    set<ItemSet> candidates = GenerateCandidates(initialCandidates, 2, filter, 1);
    ASSERT_TRUE(CheckSet("1,3 2,3 2,5 3,5", candidates));

    candidates = GenerateCandidates(candidates, 3, filter, 1);
    ASSERT_TRUE(CheckSet("2,3,5", candidates));

  }
}

extern int MinAbsSup(int A, int B, int N, double E);

TEST(MinAbsSupFilter, main) {
  EXPECT_EQ(MinAbsSup(250, 250, 1000, 0.999), 81);
  EXPECT_EQ(MinAbsSup(250, 500, 1000, 0.999), 146);
  EXPECT_EQ(MinAbsSup(600, 500, 1000, 0.999), 324);
  EXPECT_EQ(MinAbsSup(500, 500, 1000, 0.999), 274);
  EXPECT_EQ(MinAbsSup(500, 1000, 1000, 0.999), 500);
  EXPECT_EQ(MinAbsSup(500, 1000, 10000, 0.999), 71);
  EXPECT_EQ(MinAbsSup(50, 1000, 10000, 0.999), 12);
  EXPECT_EQ(MinAbsSup(50, 5000, 10000, 0.999), 36);
}
<|endoftext|>


<commit_before>// Copyright (C) 2008  Timothy Moore timoore@redhat.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <osg/StateSet>
#include <osg/Texture2D>

#include "EffectCullVisitor.hxx"

#include "EffectGeode.hxx"
#include "Effect.hxx"
#include "Technique.hxx"

#include <simgear/scene/util/RenderConstants.hxx>

namespace simgear
{

using osgUtil::CullVisitor;

EffectCullVisitor::EffectCullVisitor(bool collectLights) :
    _collectLights(collectLights)
{
}

EffectCullVisitor::EffectCullVisitor(const EffectCullVisitor& rhs) :
    osg::Referenced(rhs),
    CullVisitor(rhs)
{
}

CullVisitor* EffectCullVisitor::clone() const
{
    return new EffectCullVisitor(*this);
}

void EffectCullVisitor::apply(osg::Geode& node)
{
    if (isCulled(node))
        return;
    EffectGeode *eg = dynamic_cast<EffectGeode*>(&node);
    if (!eg) {
        CullVisitor::apply(node);
        return;
    }
    if (_collectLights && ( eg->getNodeMask() & MODELLIGHT_BIT ) ) {
        _lightList.push_back( eg );
    }
    Effect* effect = eg->getEffect();
    Technique* technique = 0;
    if (!effect) {
        CullVisitor::apply(node);
        return;
    } else if (!(technique = effect->chooseTechnique(&getRenderInfo()))) {
        return;
    }
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();
    if (node_state)
        pushStateSet(node_state);
    for (EffectGeode::DrawablesIterator beginItr = eg->drawablesBegin(),
             e = eg->drawablesEnd();
         beginItr != e;
         beginItr = technique->processDrawables(beginItr, e, this,
                                                eg->isCullingActive()))
        ;
    // pop the node's state off the geostate stack.
    if (node_state)
        popStateSet();

}

void EffectCullVisitor::reset()
{
    _lightList.clear();

    osgUtil::CullVisitor::reset();
}

void EffectCullVisitor::clearBufferList()
{
    _bufferList.clear();
}

void EffectCullVisitor::addBuffer(std::string b, osg::Texture2D* tex)
{
    _bufferList.insert(std::make_pair(b,tex));
}

osg::Texture2D* EffectCullVisitor::getBuffer(std::string b)
{
    return _bufferList[b];
}

}
<commit_msg>Fix GCC 4.6 / Ubuntu compile failure.<commit_after>// Copyright (C) 2008  Timothy Moore timoore@redhat.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <osg/StateSet>
#include <osg/Texture2D>

#include "EffectCullVisitor.hxx"

#include "EffectGeode.hxx"
#include "Effect.hxx"
#include "Technique.hxx"

#include <simgear/scene/util/RenderConstants.hxx>

namespace simgear
{

using osgUtil::CullVisitor;

EffectCullVisitor::EffectCullVisitor(bool collectLights) :
    _collectLights(collectLights)
{
}

EffectCullVisitor::EffectCullVisitor(const EffectCullVisitor& rhs) :
    CullVisitor(rhs)
{
}

CullVisitor* EffectCullVisitor::clone() const
{
    return new EffectCullVisitor(*this);
}

void EffectCullVisitor::apply(osg::Geode& node)
{
    if (isCulled(node))
        return;
    EffectGeode *eg = dynamic_cast<EffectGeode*>(&node);
    if (!eg) {
        CullVisitor::apply(node);
        return;
    }
    if (_collectLights && ( eg->getNodeMask() & MODELLIGHT_BIT ) ) {
        _lightList.push_back( eg );
    }
    Effect* effect = eg->getEffect();
    Technique* technique = 0;
    if (!effect) {
        CullVisitor::apply(node);
        return;
    } else if (!(technique = effect->chooseTechnique(&getRenderInfo()))) {
        return;
    }
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();
    if (node_state)
        pushStateSet(node_state);
    for (EffectGeode::DrawablesIterator beginItr = eg->drawablesBegin(),
             e = eg->drawablesEnd();
         beginItr != e;
         beginItr = technique->processDrawables(beginItr, e, this,
                                                eg->isCullingActive()))
        ;
    // pop the node's state off the geostate stack.
    if (node_state)
        popStateSet();

}

void EffectCullVisitor::reset()
{
    _lightList.clear();

    osgUtil::CullVisitor::reset();
}

void EffectCullVisitor::clearBufferList()
{
    _bufferList.clear();
}

void EffectCullVisitor::addBuffer(std::string b, osg::Texture2D* tex)
{
    _bufferList.insert(std::make_pair(b,tex));
}

osg::Texture2D* EffectCullVisitor::getBuffer(std::string b)
{
    return _bufferList[b];
}

}
<|endoftext|>


<commit_before>//
// Name:		StyleDlg.cpp
//
// Copyright (c) 2004-2006 Virtual Terrain Project.
// Free for all uses, see license.txt for details.
//

#ifdef __GNUG__
	#pragma implementation "StyleDlg.cpp"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#include <wx/colordlg.h>
#include <wx/fontdlg.h>
#include <wx/fontenum.h>

#include "StyleDlg.h"
#include "vtlib/vtlib.h"
#include "vtdata/Features.h"
#include "vtdata/FilePath.h"
#include "vtui/Helper.h"

// WDR: class implementations

//----------------------------------------------------------------------------
// StyleDlg
//----------------------------------------------------------------------------

// WDR: event table for StyleDlg

BEGIN_EVENT_TABLE(StyleDlg,AutoDialog)
	EVT_INIT_DIALOG (StyleDlg::OnInitDialog)
	EVT_BUTTON( ID_GEOM_COLOR, StyleDlg::OnGeomColor )
	EVT_BUTTON( ID_LABEL_COLOR, StyleDlg::OnLabelColor )
	EVT_CHECKBOX( ID_GEOMETRY, StyleDlg::OnCheck )
	EVT_CHECKBOX( ID_TEXT_LABELS, StyleDlg::OnCheck )
	EVT_CHECKBOX( ID_TEXTURE_OVERLAY, StyleDlg::OnCheck )
END_EVENT_TABLE()

StyleDlg::StyleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	AutoDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function StyleDialogFunc for StyleDlg
	StyleDialogFunc( this, TRUE );

	m_pFeatureSet = NULL;
	m_bGeometry = true;
	m_GeomColor.Set(255,255,255);

	m_bTextLabels = false;
	m_LabelColor.Set(255,255,255);
	m_iTextField = 0;
	m_iColorField = 0;
	m_fLabelHeight = 0.0f;
	m_fLabelSize = 0.0f;

	AddValidator(ID_FEATURE_TYPE, &m_strFeatureType);

	AddValidator(ID_GEOMETRY, &m_bGeometry);
	AddNumValidator(ID_GEOM_HEIGHT, &m_fGeomHeight);
	AddNumValidator(ID_LINE_WIDTH, &m_fLineWidth);
	AddValidator(ID_TESSELLATE, &m_bTessellate);

	AddValidator(ID_TEXT_LABELS, &m_bTextLabels);
	AddValidator(ID_TEXT_FIELD, &m_iTextField);
	AddValidator(ID_COLOR_FIELD, &m_iColorField);
	AddNumValidator(ID_LABEL_HEIGHT, &m_fLabelHeight);
	AddNumValidator(ID_LABEL_SIZE, &m_fLabelSize);
	AddValidator(ID_FONT, &m_strFont);

	AddValidator(ID_TEXTURE_OVERLAY, &m_bTextureOverlay);
	GetTextureMode()->Clear();
	GetTextureMode()->Append(_("ADD"));
	GetTextureMode()->Append(_("MODULATE"));
	GetTextureMode()->Append(_("DECAL"));
	AddValidator(ID_TEXTURE_MODE, &m_strTextureMode);
}

void StyleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	RefreshFields();
	UpdateEnabling();
	UpdateColorButtons();
	wxDialog::OnInitDialog(event);
}

void StyleDlg::SetOptions(const vtStringArray &datapaths, const vtTagArray &Layer)
{
	if (m_pFeatureSet)
	{
		m_type = m_pFeatureSet->GetGeomType();
	}
	else
	{
		// without a featureset, we need the actual file location
		vtString strFilename = Layer.GetValueString("Filename");
		m_strResolved = strFilename;
		m_strResolved = FindFileOnPaths(datapaths, m_strResolved);
		if (m_strResolved == "")
		{
			vtString path = "PointData/";
			m_strResolved = path + strFilename;
			m_strResolved = FindFileOnPaths(datapaths, m_strResolved);
		}

		m_type = GetFeatureGeomType(m_strResolved);

		// try to load field list (there may or may not be a DBF)
		m_DummyFeatures.LoadFieldInfoFromDBF(m_strResolved);

		m_pFeatureSet = &m_DummyFeatures;
	}

	m_bGeometry = Layer.GetValueBool("Geometry");
	if (!Layer.GetValueRGBi("GeomColor", m_GeomColor))
		m_GeomColor.Set(255,255,255);
	if (!Layer.GetValueFloat("GeomHeight", m_fGeomHeight))
		m_fGeomHeight = 1;
	if (!Layer.GetValueFloat("LineWidth", m_fLineWidth))
		m_fLineWidth = 1;
	m_bTessellate = Layer.GetValueBool("Tessellate");

	m_bTextLabels = Layer.GetValueBool("Labels");
	if (!Layer.GetValueRGBi("LabelColor", m_LabelColor))
		m_LabelColor.Set(255,255,255);

	if (!Layer.GetValueInt("TextFieldIndex", m_iTextField))
		m_iTextField = -1;
	if (!Layer.GetValueInt("ColorFieldIndex", m_iColorField))
		m_iColorField = -1;

	if (!Layer.GetValueFloat("Elevation", m_fLabelHeight))
		m_fLabelHeight= 0;
	if (!Layer.GetValueFloat("LabelSize", m_fLabelSize))
		m_fLabelSize = 20;

	vtString font;
	if (Layer.GetValueString("Font", font))
		m_strFont = wxString(font, wxConvUTF8);
	else
		m_strFont = _T("Arial.ttf");

	m_bTextureOverlay = Layer.GetValueBool("TextureOverlay");
	if (m_bTextureOverlay)
	{
		vtString modename = Layer.GetValueString("TextureMode");
		m_strTextureMode = wxString(modename, wxConvUTF8);
	}
	else
		m_strTextureMode = _T("");
}

void StyleDlg::GetOptions(vtTagArray &pLayer)
{
	pLayer.SetValueBool("Geometry", m_bGeometry, true);
	if (m_bGeometry)
	{
		pLayer.SetValueRGBi("GeomColor", m_GeomColor, true);
		if (!GeometryTypeIs3D(m_type))
			pLayer.SetValueFloat("GeomHeight", m_fGeomHeight);
		pLayer.SetValueFloat("LineWidth", m_fLineWidth);
	}
	else
	{
		pLayer.RemoveTag("GeomColor");
		pLayer.RemoveTag("GeomHeight");
		pLayer.RemoveTag("LineWidth");
	}

	if (m_bGeometry && m_type != wkbPoint && m_type != wkbPoint25D)
		pLayer.SetValueBool("Tessellate", m_bTessellate);
	else
		pLayer.RemoveTag("Tessellate");

	pLayer.SetValueBool("Labels", m_bTextLabels, true);
	if (m_bTextLabels)
	{
		pLayer.SetValueRGBi("LabelColor", m_LabelColor, true);
		pLayer.SetValueInt("TextFieldIndex", m_iTextField, true);
		pLayer.SetValueInt("ColorFieldIndex", m_iColorField, true);
		pLayer.SetValueFloat("Elevation", m_fLabelHeight, true);
		pLayer.SetValueFloat("LabelSize", m_fLabelSize, true);
		pLayer.SetValueString("Font", (const char *) m_strFont.mb_str(wxConvUTF8), true);
	}
	else
	{
		pLayer.RemoveTag("LabelColor");
		pLayer.RemoveTag("TextFieldIndex");
		pLayer.RemoveTag("ColorFieldIndex");
		pLayer.RemoveTag("Elevation");
		pLayer.RemoveTag("LabelSize");
		pLayer.RemoveTag("Font");
	}

	if (m_bTextureOverlay)
	{
		pLayer.SetValueBool("TextureOverlay", m_bTextureOverlay, true);
		vtString modename = m_strTextureMode.mb_str(wxConvUTF8);
		pLayer.SetValueString("TextureMode", modename);
	}
	else
	{
		pLayer.RemoveTag("TextureOverlay");
		pLayer.RemoveTag("TextureMode");
	}
}

void StyleDlg::RefreshFields()
{
	GetTextField()->Clear();
	GetColorField()->Clear();
	GetColorField()->Append(_("(none)"));

	if (!m_pFeatureSet)
		return;

	m_strFeatureType = wxString(OGRGeometryTypeToName(m_type), wxConvUTF8);
	int i, num = m_pFeatureSet->GetNumFields();
	for (i = 0; i < num; i++)
	{
		const Field *field = m_pFeatureSet->GetField(i);
		wxString field_name(field->m_name, wxConvUTF8);
		GetTextField()->Append(field_name);
		GetColorField()->Append(field_name);
	}
	if (num)
	{
		if (m_iTextField < 0)
			m_iTextField = 0;
		if (m_iTextField > num-1)
			m_iTextField = num-1;
		if (m_iColorField < 0)
			m_iColorField = 0;
		if (m_iColorField > num-1)
			m_iColorField = num-1;
	}
}

void StyleDlg::UpdateEnabling()
{
	GetGeometry()->Enable(m_type != wkbPoint && m_type != wkbPoint25D);
	GetGeomColor()->Enable(m_bGeometry);
	GetGeomHeight()->Enable(m_bGeometry && !GeometryTypeIs3D(m_type));
	GetLineWidth()->Enable(m_bGeometry);
	GetTessellate()->Enable(m_bGeometry && m_type != wkbPoint && m_type != wkbPoint25D);

	GetLabelColor()->Enable(m_bTextLabels);
	GetTextField()->Enable(m_bTextLabels);
	GetColorField()->Enable(m_bTextLabels && m_pFeatureSet->GetNumFields() > 1);
	GetLabelSize()->Enable(m_bTextLabels);
	GetLabelHeight()->Enable(m_bTextLabels);
	GetFont()->Enable(m_bTextLabels);

	GetTextureOverlay()->Enable(m_type == wkbPolygon);
	GetTextureMode()->Enable(m_bTextureOverlay);
}

void StyleDlg::UpdateColorButtons()
{
	FillWithColor(GetGeomColor(), m_GeomColor);
	FillWithColor(GetLabelColor(), m_LabelColor);
}

RGBi StyleDlg::AskColor(const RGBi &input)
{
	m_Colour.Set(input.r, input.g, input.b);
	m_ColourData.SetChooseFull(true);
	m_ColourData.SetColour(m_Colour);

	wxColourDialog dlg(this, &m_ColourData);
	if (dlg.ShowModal() == wxID_OK)
	{
		m_ColourData = dlg.GetColourData();
		m_Colour = m_ColourData.GetColour();
		return RGBi(m_Colour.Red(), m_Colour.Green(), m_Colour.Blue());
	}
	else
		return RGBi(-1,-1,-1);
}

// WDR: handler implementations for StyleDlg

void StyleDlg::OnCheck( wxCommandEvent &event )
{
	TransferDataFromWindow();
	UpdateEnabling();
}

void StyleDlg::OnGeomColor( wxCommandEvent &event )
{
	RGBi result = AskColor(m_GeomColor);
	if (result.r == -1)
		return;
	m_GeomColor = result;
	UpdateColorButtons();
}

void StyleDlg::OnLabelColor( wxCommandEvent &event )
{
	RGBi result = AskColor(m_LabelColor);
	if (result.r == -1)
		return;
	m_LabelColor = result;
	UpdateColorButtons();
}

<commit_msg>add string cast for gcc<commit_after>//
// Name:		StyleDlg.cpp
//
// Copyright (c) 2004-2006 Virtual Terrain Project.
// Free for all uses, see license.txt for details.
//

#ifdef __GNUG__
	#pragma implementation "StyleDlg.cpp"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#include <wx/colordlg.h>
#include <wx/fontdlg.h>
#include <wx/fontenum.h>

#include "StyleDlg.h"
#include "vtlib/vtlib.h"
#include "vtdata/Features.h"
#include "vtdata/FilePath.h"
#include "vtui/Helper.h"

// WDR: class implementations

//----------------------------------------------------------------------------
// StyleDlg
//----------------------------------------------------------------------------

// WDR: event table for StyleDlg

BEGIN_EVENT_TABLE(StyleDlg,AutoDialog)
	EVT_INIT_DIALOG (StyleDlg::OnInitDialog)
	EVT_BUTTON( ID_GEOM_COLOR, StyleDlg::OnGeomColor )
	EVT_BUTTON( ID_LABEL_COLOR, StyleDlg::OnLabelColor )
	EVT_CHECKBOX( ID_GEOMETRY, StyleDlg::OnCheck )
	EVT_CHECKBOX( ID_TEXT_LABELS, StyleDlg::OnCheck )
	EVT_CHECKBOX( ID_TEXTURE_OVERLAY, StyleDlg::OnCheck )
END_EVENT_TABLE()

StyleDlg::StyleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	AutoDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function StyleDialogFunc for StyleDlg
	StyleDialogFunc( this, TRUE );

	m_pFeatureSet = NULL;
	m_bGeometry = true;
	m_GeomColor.Set(255,255,255);

	m_bTextLabels = false;
	m_LabelColor.Set(255,255,255);
	m_iTextField = 0;
	m_iColorField = 0;
	m_fLabelHeight = 0.0f;
	m_fLabelSize = 0.0f;

	AddValidator(ID_FEATURE_TYPE, &m_strFeatureType);

	AddValidator(ID_GEOMETRY, &m_bGeometry);
	AddNumValidator(ID_GEOM_HEIGHT, &m_fGeomHeight);
	AddNumValidator(ID_LINE_WIDTH, &m_fLineWidth);
	AddValidator(ID_TESSELLATE, &m_bTessellate);

	AddValidator(ID_TEXT_LABELS, &m_bTextLabels);
	AddValidator(ID_TEXT_FIELD, &m_iTextField);
	AddValidator(ID_COLOR_FIELD, &m_iColorField);
	AddNumValidator(ID_LABEL_HEIGHT, &m_fLabelHeight);
	AddNumValidator(ID_LABEL_SIZE, &m_fLabelSize);
	AddValidator(ID_FONT, &m_strFont);

	AddValidator(ID_TEXTURE_OVERLAY, &m_bTextureOverlay);
	GetTextureMode()->Clear();
	GetTextureMode()->Append(_("ADD"));
	GetTextureMode()->Append(_("MODULATE"));
	GetTextureMode()->Append(_("DECAL"));
	AddValidator(ID_TEXTURE_MODE, &m_strTextureMode);
}

void StyleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	RefreshFields();
	UpdateEnabling();
	UpdateColorButtons();
	wxDialog::OnInitDialog(event);
}

void StyleDlg::SetOptions(const vtStringArray &datapaths, const vtTagArray &Layer)
{
	if (m_pFeatureSet)
	{
		m_type = m_pFeatureSet->GetGeomType();
	}
	else
	{
		// without a featureset, we need the actual file location
		vtString strFilename = Layer.GetValueString("Filename");
		m_strResolved = strFilename;
		m_strResolved = FindFileOnPaths(datapaths, m_strResolved);
		if (m_strResolved == "")
		{
			vtString path = "PointData/";
			m_strResolved = path + strFilename;
			m_strResolved = FindFileOnPaths(datapaths, m_strResolved);
		}

		m_type = GetFeatureGeomType(m_strResolved);

		// try to load field list (there may or may not be a DBF)
		m_DummyFeatures.LoadFieldInfoFromDBF(m_strResolved);

		m_pFeatureSet = &m_DummyFeatures;
	}

	m_bGeometry = Layer.GetValueBool("Geometry");
	if (!Layer.GetValueRGBi("GeomColor", m_GeomColor))
		m_GeomColor.Set(255,255,255);
	if (!Layer.GetValueFloat("GeomHeight", m_fGeomHeight))
		m_fGeomHeight = 1;
	if (!Layer.GetValueFloat("LineWidth", m_fLineWidth))
		m_fLineWidth = 1;
	m_bTessellate = Layer.GetValueBool("Tessellate");

	m_bTextLabels = Layer.GetValueBool("Labels");
	if (!Layer.GetValueRGBi("LabelColor", m_LabelColor))
		m_LabelColor.Set(255,255,255);

	if (!Layer.GetValueInt("TextFieldIndex", m_iTextField))
		m_iTextField = -1;
	if (!Layer.GetValueInt("ColorFieldIndex", m_iColorField))
		m_iColorField = -1;

	if (!Layer.GetValueFloat("Elevation", m_fLabelHeight))
		m_fLabelHeight= 0;
	if (!Layer.GetValueFloat("LabelSize", m_fLabelSize))
		m_fLabelSize = 20;

	vtString font;
	if (Layer.GetValueString("Font", font))
		m_strFont = wxString(font, wxConvUTF8);
	else
		m_strFont = _T("Arial.ttf");

	m_bTextureOverlay = Layer.GetValueBool("TextureOverlay");
	if (m_bTextureOverlay)
	{
		vtString modename = Layer.GetValueString("TextureMode");
		m_strTextureMode = wxString(modename, wxConvUTF8);
	}
	else
		m_strTextureMode = _T("");
}

void StyleDlg::GetOptions(vtTagArray &pLayer)
{
	pLayer.SetValueBool("Geometry", m_bGeometry, true);
	if (m_bGeometry)
	{
		pLayer.SetValueRGBi("GeomColor", m_GeomColor, true);
		if (!GeometryTypeIs3D(m_type))
			pLayer.SetValueFloat("GeomHeight", m_fGeomHeight);
		pLayer.SetValueFloat("LineWidth", m_fLineWidth);
	}
	else
	{
		pLayer.RemoveTag("GeomColor");
		pLayer.RemoveTag("GeomHeight");
		pLayer.RemoveTag("LineWidth");
	}

	if (m_bGeometry && m_type != wkbPoint && m_type != wkbPoint25D)
		pLayer.SetValueBool("Tessellate", m_bTessellate);
	else
		pLayer.RemoveTag("Tessellate");

	pLayer.SetValueBool("Labels", m_bTextLabels, true);
	if (m_bTextLabels)
	{
		pLayer.SetValueRGBi("LabelColor", m_LabelColor, true);
		pLayer.SetValueInt("TextFieldIndex", m_iTextField, true);
		pLayer.SetValueInt("ColorFieldIndex", m_iColorField, true);
		pLayer.SetValueFloat("Elevation", m_fLabelHeight, true);
		pLayer.SetValueFloat("LabelSize", m_fLabelSize, true);
		pLayer.SetValueString("Font", (const char *) m_strFont.mb_str(wxConvUTF8), true);
	}
	else
	{
		pLayer.RemoveTag("LabelColor");
		pLayer.RemoveTag("TextFieldIndex");
		pLayer.RemoveTag("ColorFieldIndex");
		pLayer.RemoveTag("Elevation");
		pLayer.RemoveTag("LabelSize");
		pLayer.RemoveTag("Font");
	}

	if (m_bTextureOverlay)
	{
		pLayer.SetValueBool("TextureOverlay", m_bTextureOverlay, true);
		vtString modename = (const char *) m_strTextureMode.mb_str(wxConvUTF8);
		pLayer.SetValueString("TextureMode", modename);
	}
	else
	{
		pLayer.RemoveTag("TextureOverlay");
		pLayer.RemoveTag("TextureMode");
	}
}

void StyleDlg::RefreshFields()
{
	GetTextField()->Clear();
	GetColorField()->Clear();
	GetColorField()->Append(_("(none)"));

	if (!m_pFeatureSet)
		return;

	m_strFeatureType = wxString(OGRGeometryTypeToName(m_type), wxConvUTF8);
	int i, num = m_pFeatureSet->GetNumFields();
	for (i = 0; i < num; i++)
	{
		const Field *field = m_pFeatureSet->GetField(i);
		wxString field_name(field->m_name, wxConvUTF8);
		GetTextField()->Append(field_name);
		GetColorField()->Append(field_name);
	}
	if (num)
	{
		if (m_iTextField < 0)
			m_iTextField = 0;
		if (m_iTextField > num-1)
			m_iTextField = num-1;
		if (m_iColorField < 0)
			m_iColorField = 0;
		if (m_iColorField > num-1)
			m_iColorField = num-1;
	}
}

void StyleDlg::UpdateEnabling()
{
	GetGeometry()->Enable(m_type != wkbPoint && m_type != wkbPoint25D);
	GetGeomColor()->Enable(m_bGeometry);
	GetGeomHeight()->Enable(m_bGeometry && !GeometryTypeIs3D(m_type));
	GetLineWidth()->Enable(m_bGeometry);
	GetTessellate()->Enable(m_bGeometry && m_type != wkbPoint && m_type != wkbPoint25D);

	GetLabelColor()->Enable(m_bTextLabels);
	GetTextField()->Enable(m_bTextLabels);
	GetColorField()->Enable(m_bTextLabels && m_pFeatureSet->GetNumFields() > 1);
	GetLabelSize()->Enable(m_bTextLabels);
	GetLabelHeight()->Enable(m_bTextLabels);
	GetFont()->Enable(m_bTextLabels);

	GetTextureOverlay()->Enable(m_type == wkbPolygon);
	GetTextureMode()->Enable(m_bTextureOverlay);
}

void StyleDlg::UpdateColorButtons()
{
	FillWithColor(GetGeomColor(), m_GeomColor);
	FillWithColor(GetLabelColor(), m_LabelColor);
}

RGBi StyleDlg::AskColor(const RGBi &input)
{
	m_Colour.Set(input.r, input.g, input.b);
	m_ColourData.SetChooseFull(true);
	m_ColourData.SetColour(m_Colour);

	wxColourDialog dlg(this, &m_ColourData);
	if (dlg.ShowModal() == wxID_OK)
	{
		m_ColourData = dlg.GetColourData();
		m_Colour = m_ColourData.GetColour();
		return RGBi(m_Colour.Red(), m_Colour.Green(), m_Colour.Blue());
	}
	else
		return RGBi(-1,-1,-1);
}

// WDR: handler implementations for StyleDlg

void StyleDlg::OnCheck( wxCommandEvent &event )
{
	TransferDataFromWindow();
	UpdateEnabling();
}

void StyleDlg::OnGeomColor( wxCommandEvent &event )
{
	RGBi result = AskColor(m_GeomColor);
	if (result.r == -1)
		return;
	m_GeomColor = result;
	UpdateColorButtons();
}

void StyleDlg::OnLabelColor( wxCommandEvent &event )
{
	RGBi result = AskColor(m_LabelColor);
	if (result.r == -1)
		return;
	m_LabelColor = result;
	UpdateColorButtons();
}

<|endoftext|>