<commit_before>/*
 * Copyright (c) 2015 - 2021, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <vector>
#include <memory>
#include <map>

#include "geopm_topo.h"

#include "Helper.hpp"
#include "ServiceIOGroup.hpp"
#include "MockServiceProxy.hpp"
#include "MockPlatformTopo.hpp"
#include "geopm_test.hpp"

using geopm::signal_info_s;
using geopm::control_info_s;
using geopm::ServiceIOGroup;
using geopm::Exception;
using testing::AtLeast;
using testing::Return;
using testing::Throw;
using testing::_;

class ServiceIOGroupTest : public :: testing:: Test
{
    protected:
        void SetUp();

        std::unique_ptr<ServiceIOGroup> m_serviceio_group;
        std::shared_ptr<MockServiceProxy> m_proxy;
        std::shared_ptr<MockPlatformTopo> m_topo;

        int m_num_package = 2;
        int m_num_core = 4;
        int m_num_cpu = 16;

        std::vector<std::string> m_expected_signals;
        std::vector<std::string> m_expected_controls;
        std::map<std::string, signal_info_s> m_signal_info;
        std::map<std::string, control_info_s> m_control_info;
};

void ServiceIOGroupTest::SetUp()
{
    m_topo = make_topo(m_num_package, m_num_core, m_num_cpu);
    m_proxy = std::make_shared<MockServiceProxy>();
    EXPECT_CALL(*m_topo, num_domain(_)).Times(AtLeast(0));

    m_expected_signals = {"signal1", "signal2"};
    m_expected_controls = {"control1", "control2"};

    // signal_info_s: (str)name, (str)desc, (int)domain, (int)agg, (int)string_format, (int)behavior
    m_signal_info =
        {{m_expected_signals[0],
         {m_expected_signals[0], "1 Signal", 0, 0, 0, 0}},
         {m_expected_signals[1],
         {m_expected_signals[1], "2 Signal", 1, 1, 1, 1}},
        };

    // control_info_s: (str)name, (str)desc, (int)domain
    m_control_info =
        {{m_expected_controls[0],
         {m_expected_controls[0], "1 Control", 0}},
         {m_expected_controls[1],
         {m_expected_controls[1], "2 Control", 1}},
        };

    EXPECT_CALL(*m_proxy, platform_get_user_access(_, _))
        .WillRepeatedly([this]
                        (std::vector<std::string> &signals,
                         std::vector<std::string> &controls) {
            signals = m_expected_signals;
            controls = m_expected_controls;
        });

    std::vector<signal_info_s> expected_signal_info = {m_signal_info[m_expected_signals[0]],
                                                       m_signal_info[m_expected_signals[1]]};
    std::vector<control_info_s> expected_control_info = {m_control_info[m_expected_controls[0]],
                                                         m_control_info[m_expected_controls[1]]};

    EXPECT_CALL(*m_proxy, platform_get_signal_info(m_expected_signals))
        .WillOnce(Return(expected_signal_info));
    EXPECT_CALL(*m_proxy, platform_get_control_info(m_expected_controls))
        .WillOnce(Return(expected_control_info));

    EXPECT_CALL(*m_proxy, platform_open_session());
    EXPECT_CALL(*m_proxy, platform_close_session());

    m_serviceio_group = geopm::make_unique<ServiceIOGroup>(*m_topo, m_proxy);
}

TEST_F(ServiceIOGroupTest, signal_control_info)
{
    auto signal_names = m_serviceio_group->signal_names();
    auto control_names = m_serviceio_group->control_names();

    for (auto sig : m_expected_signals) {
        EXPECT_TRUE(m_serviceio_group->is_valid_signal(sig));
        EXPECT_TRUE(signal_names.find(sig) != signal_names.end());
        EXPECT_TRUE(signal_names.find("SERVICE::" + sig) != signal_names.end());
        EXPECT_EQ(m_signal_info[sig].description, m_serviceio_group->signal_description(sig));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->signal_description("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");

    for (auto con : m_expected_controls) {
        EXPECT_TRUE(m_serviceio_group->is_valid_control(con));
        EXPECT_TRUE(control_names.find(con) != control_names.end());
        EXPECT_TRUE(control_names.find("SERVICE::" + con) != control_names.end());
        EXPECT_EQ(m_control_info[con].description, m_serviceio_group->control_description(con));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->control_description("BAD CONTROL"),
                               GEOPM_ERROR_INVALID,
                               "BAD CONTROL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, domain_type)
{
    for (unsigned ii = 0; ii < m_expected_signals.size(); ++ii) {
        EXPECT_EQ(ii, m_serviceio_group->signal_domain_type(m_expected_signals.at(ii)));
        EXPECT_EQ(ii, m_serviceio_group->signal_domain_type("SERVICE::" + m_expected_signals.at(ii)));
    }
    for (unsigned ii = 0; ii < m_expected_controls.size(); ++ii) {
        EXPECT_EQ(ii, m_serviceio_group->control_domain_type(m_expected_controls.at(ii)));
        EXPECT_EQ(ii, m_serviceio_group->control_domain_type("SERVICE::" + m_expected_controls.at(ii)));
    }
    EXPECT_EQ(GEOPM_DOMAIN_INVALID, m_serviceio_group->signal_domain_type("BAD SIGNAL"));
    EXPECT_EQ(GEOPM_DOMAIN_INVALID, m_serviceio_group->control_domain_type("BAD CONTROL"));
}

TEST_F(ServiceIOGroupTest, read_signal_behavior)
{
    for (unsigned ii = 0; ii < m_expected_signals.size(); ++ii) {
        EXPECT_CALL(*m_proxy, platform_read_signal(m_expected_signals.at(ii), ii, ii))
            .WillOnce(Return(42))
            .WillOnce(Return(7));
        EXPECT_EQ(42, m_serviceio_group->read_signal(m_expected_signals.at(ii), ii, ii));
        EXPECT_EQ(7, m_serviceio_group->read_signal("SERVICE::" + m_expected_signals.at(ii), ii, ii));
        EXPECT_EQ(ii, m_serviceio_group->signal_behavior(m_expected_signals.at(ii)));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->signal_behavior("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, write_control)
{
    for (unsigned ii = 0; ii < m_expected_controls.size(); ++ii) {
        EXPECT_CALL(*m_proxy, platform_write_control(m_expected_controls.at(ii), ii, ii, 42));
        EXPECT_NO_THROW(m_serviceio_group->write_control(m_expected_controls.at(ii), ii, ii, 42));
        EXPECT_CALL(*m_proxy, platform_write_control(m_expected_controls.at(ii), ii, ii, 7));
        EXPECT_NO_THROW(m_serviceio_group->write_control("SERVICE::" + m_expected_controls.at(ii),
                                                         ii, ii, 7));
    }
}

TEST_F(ServiceIOGroupTest, valid_signal_aggregation)
{
    std::function<double(const std::vector<double> &)> func;
    func = m_serviceio_group->agg_function("signal1");
    EXPECT_TRUE(is_agg_sum(func));
    func = m_serviceio_group->agg_function("signal2");
    EXPECT_TRUE(is_agg_average(func));
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->agg_function("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, valid_format_function)
{
    std::function<std::string(double)> func;
    func = m_serviceio_group->format_function("signal1");
    EXPECT_TRUE(is_format_double(func));
    func = m_serviceio_group->format_function("signal2");
    EXPECT_TRUE(is_format_integer(func));
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->format_function("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, push_signal)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->push_signal("BAD SIGNAL", 0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::push_signal()");
}

TEST_F(ServiceIOGroupTest, push_control)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->push_control("BAD CONTROL", 0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::push_control()");
}

TEST_F(ServiceIOGroupTest, read_batch)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->read_batch(),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::read_batch()");
}

TEST_F(ServiceIOGroupTest, write_batch)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->write_batch(),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::write_batch()");
}

TEST_F(ServiceIOGroupTest, sample)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->sample(0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::sample()");
}

TEST_F(ServiceIOGroupTest, adjust)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->adjust(0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::adjust()");
}

<commit_msg>Fix more signed/unsigned comparisons in ServiceIOGroup<commit_after>/*
 * Copyright (c) 2015 - 2021, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <vector>
#include <memory>
#include <map>

#include "geopm_topo.h"

#include "Helper.hpp"
#include "ServiceIOGroup.hpp"
#include "MockServiceProxy.hpp"
#include "MockPlatformTopo.hpp"
#include "geopm_test.hpp"

using geopm::signal_info_s;
using geopm::control_info_s;
using geopm::ServiceIOGroup;
using geopm::Exception;
using testing::AtLeast;
using testing::Return;
using testing::Throw;
using testing::_;

class ServiceIOGroupTest : public :: testing:: Test
{
    protected:
        void SetUp();

        std::unique_ptr<ServiceIOGroup> m_serviceio_group;
        std::shared_ptr<MockServiceProxy> m_proxy;
        std::shared_ptr<MockPlatformTopo> m_topo;

        int m_num_package = 2;
        int m_num_core = 4;
        int m_num_cpu = 16;

        std::vector<std::string> m_expected_signals;
        std::vector<std::string> m_expected_controls;
        std::map<std::string, signal_info_s> m_signal_info;
        std::map<std::string, control_info_s> m_control_info;
};

void ServiceIOGroupTest::SetUp()
{
    m_topo = make_topo(m_num_package, m_num_core, m_num_cpu);
    m_proxy = std::make_shared<MockServiceProxy>();
    EXPECT_CALL(*m_topo, num_domain(_)).Times(AtLeast(0));

    m_expected_signals = {"signal1", "signal2"};
    m_expected_controls = {"control1", "control2"};

    // signal_info_s: (str)name, (str)desc, (int)domain, (int)agg, (int)string_format, (int)behavior
    m_signal_info =
        {{m_expected_signals[0],
         {m_expected_signals[0], "1 Signal", 0, 0, 0, 0}},
         {m_expected_signals[1],
         {m_expected_signals[1], "2 Signal", 1, 1, 1, 1}},
        };

    // control_info_s: (str)name, (str)desc, (int)domain
    m_control_info =
        {{m_expected_controls[0],
         {m_expected_controls[0], "1 Control", 0}},
         {m_expected_controls[1],
         {m_expected_controls[1], "2 Control", 1}},
        };

    EXPECT_CALL(*m_proxy, platform_get_user_access(_, _))
        .WillRepeatedly([this]
                        (std::vector<std::string> &signals,
                         std::vector<std::string> &controls) {
            signals = m_expected_signals;
            controls = m_expected_controls;
        });

    std::vector<signal_info_s> expected_signal_info = {m_signal_info[m_expected_signals[0]],
                                                       m_signal_info[m_expected_signals[1]]};
    std::vector<control_info_s> expected_control_info = {m_control_info[m_expected_controls[0]],
                                                         m_control_info[m_expected_controls[1]]};

    EXPECT_CALL(*m_proxy, platform_get_signal_info(m_expected_signals))
        .WillOnce(Return(expected_signal_info));
    EXPECT_CALL(*m_proxy, platform_get_control_info(m_expected_controls))
        .WillOnce(Return(expected_control_info));

    EXPECT_CALL(*m_proxy, platform_open_session());
    EXPECT_CALL(*m_proxy, platform_close_session());

    m_serviceio_group = geopm::make_unique<ServiceIOGroup>(*m_topo, m_proxy);
}

TEST_F(ServiceIOGroupTest, signal_control_info)
{
    auto signal_names = m_serviceio_group->signal_names();
    auto control_names = m_serviceio_group->control_names();

    for (auto sig : m_expected_signals) {
        EXPECT_TRUE(m_serviceio_group->is_valid_signal(sig));
        EXPECT_TRUE(signal_names.find(sig) != signal_names.end());
        EXPECT_TRUE(signal_names.find("SERVICE::" + sig) != signal_names.end());
        EXPECT_EQ(m_signal_info[sig].description, m_serviceio_group->signal_description(sig));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->signal_description("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");

    for (auto con : m_expected_controls) {
        EXPECT_TRUE(m_serviceio_group->is_valid_control(con));
        EXPECT_TRUE(control_names.find(con) != control_names.end());
        EXPECT_TRUE(control_names.find("SERVICE::" + con) != control_names.end());
        EXPECT_EQ(m_control_info[con].description, m_serviceio_group->control_description(con));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->control_description("BAD CONTROL"),
                               GEOPM_ERROR_INVALID,
                               "BAD CONTROL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, domain_type)
{
    for (int ii = 0; ii < (int)m_expected_signals.size(); ++ii) {
        EXPECT_EQ(ii, m_serviceio_group->signal_domain_type(m_expected_signals.at(ii)));
        EXPECT_EQ(ii, m_serviceio_group->signal_domain_type("SERVICE::" + m_expected_signals.at(ii)));
    }
    for (int ii = 0; ii < (int)m_expected_controls.size(); ++ii) {
        EXPECT_EQ(ii, m_serviceio_group->control_domain_type(m_expected_controls.at(ii)));
        EXPECT_EQ(ii, m_serviceio_group->control_domain_type("SERVICE::" + m_expected_controls.at(ii)));
    }
    EXPECT_EQ(GEOPM_DOMAIN_INVALID, m_serviceio_group->signal_domain_type("BAD SIGNAL"));
    EXPECT_EQ(GEOPM_DOMAIN_INVALID, m_serviceio_group->control_domain_type("BAD CONTROL"));
}

TEST_F(ServiceIOGroupTest, read_signal_behavior)
{
    for (unsigned ii = 0; ii < m_expected_signals.size(); ++ii) {
        EXPECT_CALL(*m_proxy, platform_read_signal(m_expected_signals.at(ii), ii, ii))
            .WillOnce(Return(42))
            .WillOnce(Return(7));
        EXPECT_EQ(42, m_serviceio_group->read_signal(m_expected_signals.at(ii), ii, ii));
        EXPECT_EQ(7, m_serviceio_group->read_signal("SERVICE::" + m_expected_signals.at(ii), ii, ii));
        EXPECT_EQ((int)ii, m_serviceio_group->signal_behavior(m_expected_signals.at(ii)));
    }
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->signal_behavior("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, write_control)
{
    for (unsigned ii = 0; ii < m_expected_controls.size(); ++ii) {
        EXPECT_CALL(*m_proxy, platform_write_control(m_expected_controls.at(ii), ii, ii, 42));
        EXPECT_NO_THROW(m_serviceio_group->write_control(m_expected_controls.at(ii), ii, ii, 42));
        EXPECT_CALL(*m_proxy, platform_write_control(m_expected_controls.at(ii), ii, ii, 7));
        EXPECT_NO_THROW(m_serviceio_group->write_control("SERVICE::" + m_expected_controls.at(ii),
                                                         ii, ii, 7));
    }
}

TEST_F(ServiceIOGroupTest, valid_signal_aggregation)
{
    std::function<double(const std::vector<double> &)> func;
    func = m_serviceio_group->agg_function("signal1");
    EXPECT_TRUE(is_agg_sum(func));
    func = m_serviceio_group->agg_function("signal2");
    EXPECT_TRUE(is_agg_average(func));
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->agg_function("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, valid_format_function)
{
    std::function<std::string(double)> func;
    func = m_serviceio_group->format_function("signal1");
    EXPECT_TRUE(is_format_double(func));
    func = m_serviceio_group->format_function("signal2");
    EXPECT_TRUE(is_format_integer(func));
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->format_function("BAD SIGNAL"),
                               GEOPM_ERROR_INVALID,
                               "BAD SIGNAL not valid for ServiceIOGroup");
}

TEST_F(ServiceIOGroupTest, push_signal)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->push_signal("BAD SIGNAL", 0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::push_signal()");
}

TEST_F(ServiceIOGroupTest, push_control)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->push_control("BAD CONTROL", 0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::push_control()");
}

TEST_F(ServiceIOGroupTest, read_batch)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->read_batch(),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::read_batch()");
}

TEST_F(ServiceIOGroupTest, write_batch)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->write_batch(),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::write_batch()");
}

TEST_F(ServiceIOGroupTest, sample)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->sample(0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::sample()");
}

TEST_F(ServiceIOGroupTest, adjust)
{
    GEOPM_EXPECT_THROW_MESSAGE(m_serviceio_group->adjust(0, 0),
                               GEOPM_ERROR_NOT_IMPLEMENTED,
                               "ServiceIOGroup::adjust()");
}

<|endoftext|>


<commit_before>/*
 * Scope Guard
 * Copyright (C) 2017  offa
 *
 * This file is part of Scope Guard.
 *
 * Scope Guard is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scope Guard 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 Scope Guard.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "unique_resource.h"
#include "CallMocks.h"
#include <catch.hpp>
#include <trompeloeil.hpp>

using namespace mock;
using namespace trompeloeil;

namespace
{
    CallMock m;

    void deleter(Handle h)
    {
        m.deleter(h);
    }
}

TEST_CASE("construction with move", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    static_cast<void>(guard);
}

TEST_CASE("construction with copy", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    const Handle h{3};
    const auto d = [](auto v) { m.deleter(v); };
    auto guard = sr::make_unique_resource(h, d);
    static_cast<void>(guard);
}

TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]")
{
    REQUIRE_THROWS([] {
        const ThrowOnCopyMock noMove;
        const auto d = [](const auto&) { m.deleter(3); };
        REQUIRE_CALL(m, deleter(3));

        sr::unique_resource<decltype(noMove), decltype(d)> guard{noMove, d};
        static_cast<void>(guard);
    }());
}

TEST_CASE("move-construction with move", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto movedFrom = sr::make_unique_resource(Handle{3}, deleter);
    auto guard = std::move(movedFrom);
    CHECK(guard.get() == 3);
}

TEST_CASE("move-construction with copy", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto d = [](auto) { deleter(7); };

    const CopyMock copyMock;
    sr::unique_resource<CopyMock, decltype(d)> movedFrom{copyMock, d};
    auto guard = std::move(movedFrom);
    static_cast<void>(guard);
}

TEST_CASE("move assignment calls deleter", "[UniqueResource]")
{
    auto moveFrom = sr::make_unique_resource(Handle{3}, deleter);
    REQUIRE_CALL(m, deleter(4));

    {
        REQUIRE_CALL(m, deleter(3));
        auto guard = sr::make_unique_resource(Handle{4}, deleter);
        guard = std::move(moveFrom);
    }
}

TEST_CASE("deleter called on destruction", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    static_cast<void>(guard);
}

TEST_CASE("reset calls deleter", "[UniqueResource]")
{
    auto guard = sr::make_unique_resource(Handle{3}, deleter);

    {
        REQUIRE_CALL(m, deleter(3));
        guard.reset();
    }
}

TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3)).TIMES(0);
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    guard.release();
    guard.reset();
}

TEST_CASE("reset sets new value and calls deleter on previous", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    REQUIRE_CALL(m, deleter(7));
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    guard.reset(Handle{7});
}

TEST_CASE("reset handles exception on assignment", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    REQUIRE_CALL(m, deleter(7));
    auto d = [](const auto& v) { deleter(v.m_handle); };
    auto guard = sr::make_unique_resource(ConditialThrowOnCopyMock{3, false}, d);
    guard.reset(ConditialThrowOnCopyMock{7, true});
}

TEST_CASE("release disables deleter", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3)).TIMES(0);
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    guard.release();
}

TEST_CASE("get returns resource", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    CHECK(guard.get() == 3);
}

TEST_CASE("pointer access returns resource" "[UniqueResource]")
{
    const auto p = std::make_pair(3, 4);
    auto guard = sr::make_unique_resource(&p, [](auto*) { });
    REQUIRE(guard->first == 3);
    REQUIRE(guard->second == 4);
}

TEST_CASE("pointer dereference returns resource" "[UniqueResource]")
{
    Handle h{5};
    auto guard = sr::make_unique_resource(PtrHandle{&h}, [](auto*) { });
    REQUIRE(*guard == 5);
}

TEST_CASE("deleter access", "[UniqueResource]")
{
    auto guard = sr::make_unique_resource(Handle{3}, deleter);
    guard.release();

    {
        REQUIRE_CALL(m, deleter(8));
        guard.get_deleter()(8);
    }
}

TEST_CASE("swap", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto guard1 = sr::make_unique_resource(Handle{3}, deleter);

    {
        REQUIRE_CALL(m, deleter(3));
        auto guard2 = sr::make_unique_resource(Handle{7}, deleter);
        guard2.swap(guard1);
        REQUIRE(guard1.get() == 7);
        REQUIRE(guard2.get() == 3);
    }
}

TEST_CASE("make unique resource", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto guard = sr::make_unique_resource(Handle{7}, deleter);
    static_cast<void>(guard);
}

TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    Handle h{3};
    auto guard = sr::make_unique_resource(std::ref(h), deleter);
    static_cast<void>(guard);
}

TEST_CASE("make unique resource checked", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(4));
    auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter);
    static_cast<void>(guard);
}

TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]")
{
    auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter);
    static_cast<void>(guard);
}

<commit_msg>Test updated to use ctor directly.<commit_after>/*
 * Scope Guard
 * Copyright (C) 2017  offa
 *
 * This file is part of Scope Guard.
 *
 * Scope Guard is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scope Guard 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 Scope Guard.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "unique_resource.h"
#include "CallMocks.h"
#include <catch.hpp>
#include <trompeloeil.hpp>

using namespace mock;
using namespace trompeloeil;

namespace
{
    CallMock m;

    void deleter(Handle h)
    {
        m.deleter(h);
    }
}

TEST_CASE("construction with move", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::unique_resource{Handle{3}, deleter};
    static_cast<void>(guard);
}

TEST_CASE("construction with copy", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    const Handle h{3};
    const auto d = [](auto v) { m.deleter(v); };
    auto guard = sr::unique_resource{h, d};
    static_cast<void>(guard);
}

TEST_CASE("construction with copy calls deleter and rethrows on failed copy", "[UniqueResource]")
{
    REQUIRE_THROWS([] {
        const ThrowOnCopyMock noMove;
        const auto d = [](const auto&) { m.deleter(3); };
        REQUIRE_CALL(m, deleter(3));

        sr::unique_resource guard{noMove, d};
        static_cast<void>(guard);
    }());
}

TEST_CASE("move-construction with move", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto movedFrom = sr::unique_resource{Handle{3}, deleter};
    auto guard = std::move(movedFrom);
    CHECK(guard.get() == 3);
}

TEST_CASE("move-construction with copy", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto d = [](auto) { deleter(7); };

    const CopyMock copyMock;
    sr::unique_resource movedFrom{copyMock, d};
    auto guard = std::move(movedFrom);
    static_cast<void>(guard);
}

TEST_CASE("move assignment calls deleter", "[UniqueResource]")
{
    auto moveFrom = sr::unique_resource{Handle{3}, deleter};
    REQUIRE_CALL(m, deleter(4));

    {
        REQUIRE_CALL(m, deleter(3));
        auto guard = sr::unique_resource{Handle{4}, deleter};
        guard = std::move(moveFrom);
    }
}

TEST_CASE("deleter called on destruction", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::unique_resource{Handle{3}, deleter};
    static_cast<void>(guard);
}

TEST_CASE("reset calls deleter", "[UniqueResource]")
{
    auto guard = sr::unique_resource{Handle{3}, deleter};

    {
        REQUIRE_CALL(m, deleter(3));
        guard.reset();
    }
}

TEST_CASE("reset does not call deleter if released", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3)).TIMES(0);
    auto guard = sr::unique_resource{Handle{3}, deleter};
    guard.release();
    guard.reset();
}

TEST_CASE("reset sets new value and calls deleter on previous", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    REQUIRE_CALL(m, deleter(7));
    auto guard = sr::unique_resource{Handle{3}, deleter};
    guard.reset(Handle{7});
}

TEST_CASE("reset handles exception on assignment", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    REQUIRE_CALL(m, deleter(7));
    auto d = [](const auto& v) { deleter(v.m_handle); };
    auto guard = sr::unique_resource{ConditialThrowOnCopyMock{3, false}, d};
    guard.reset(ConditialThrowOnCopyMock{7, true});
}

TEST_CASE("release disables deleter", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3)).TIMES(0);
    auto guard = sr::unique_resource{Handle{3}, deleter};
    guard.release();
}

TEST_CASE("get returns resource", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    auto guard = sr::unique_resource{Handle{3}, deleter};
    CHECK(guard.get() == 3);
}

TEST_CASE("pointer access returns resource" "[UniqueResource]")
{
    const auto p = std::make_pair(3, 4);
    auto guard = sr::unique_resource{&p, [](auto*) { }};
    REQUIRE(guard->first == 3);
    REQUIRE(guard->second == 4);
}

TEST_CASE("pointer dereference returns resource" "[UniqueResource]")
{
    Handle h{5};
    auto guard = sr::unique_resource{PtrHandle{&h}, [](auto*) { }};
    REQUIRE(*guard == 5);
}

TEST_CASE("deleter access", "[UniqueResource]")
{
    auto guard = sr::unique_resource{Handle{3}, deleter};
    guard.release();

    {
        REQUIRE_CALL(m, deleter(8));
        guard.get_deleter()(8);
    }
}

TEST_CASE("swap", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto guard1 = sr::unique_resource(Handle{3}, deleter);

    {
        REQUIRE_CALL(m, deleter(3));
        auto guard2 = sr::unique_resource{Handle{7}, deleter};
        guard2.swap(guard1);
        REQUIRE(guard1.get() == 7);
        REQUIRE(guard2.get() == 3);
    }
}

TEST_CASE("make unique resource", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(7));
    auto guard = sr::unique_resource{Handle{7}, deleter};
    static_cast<void>(guard);
}

TEST_CASE("make unique resource with reference wrapper", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(3));
    Handle h{3};
    auto guard = sr::unique_resource{std::ref(h), deleter};
    static_cast<void>(guard);
}

TEST_CASE("make unique resource checked", "[UniqueResource]")
{
    REQUIRE_CALL(m, deleter(4));
    auto guard = sr::make_unique_resource_checked(Handle{4}, Handle{-1}, deleter);
    static_cast<void>(guard);
}

TEST_CASE("make unique resource checked releases if invalid", "[UniqueResource]")
{
    auto guard = sr::make_unique_resource_checked(Handle{-1}, Handle{-1}, deleter);
    static_cast<void>(guard);
}

<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

using namespace Halide;
using namespace Halide::Internal;
using std::string;

// Count the number of stores to a given func, and the number of calls to sin
class Counter : public IRVisitor {
    string func;

    using IRVisitor::visit;

    void visit(const Store *op) {
        IRVisitor::visit(op);
        if (op->name == func) {
            store_count++;
        }
    }

    void visit(const Call *op) {
        IRVisitor::visit(op);
        if (op->name == "sin_f32") {
            sin_count++;
        }
    }

public:
    int store_count, sin_count;
    Counter(string f) : func(f), store_count(0), sin_count(0) {}
};

// Check that the number of calls to sin is correct.
class CheckSinCount : public IRMutator {
    int correct;
public:
    using IRMutator::mutate;

    Stmt mutate(Stmt s) {
        Counter c("");
        s.accept(&c);
        if (c.sin_count != correct) {
            printf("There were %d sin calls instead of %d\n", c.sin_count, correct);
            exit(-1);
        }
        return s;
    }

    CheckSinCount(int c) : correct(c) {}
};

// Check that the number of stores to a given func is correct
class CheckStoreCount : public IRMutator {
    string func;
    int correct;
public:
    using IRMutator::mutate;

    Stmt mutate(Stmt s) {
        Counter c(func);
        s.accept(&c);
        if (c.store_count != correct) {
            printf("There were %d stores to %s instead of %d\n", c.store_count, func.c_str(), correct);
            exit(-1);
        }
        return s;
    }

    CheckStoreCount(string f, int c) : func(f), correct(c) {}
};

void count_partitions(Func g, int correct) {
    g.add_custom_lowering_pass(new CheckStoreCount(g.name(), correct));
    g.compile_jit();
}

void count_sin_calls(Func g, int correct) {
    g.add_custom_lowering_pass(new CheckSinCount(correct));
    g.compile_jit();
}

int main(int argc, char **argv) {
    Func f;
    Var x;
    f(x) = x;
    f.compute_root();

    // Halide will partition a loop into three pieces in a few
    // situations. The pieces are 1) a messy prologue, 2) a clean
    // steady state, and 3) a messy epilogue. One way to trigger this
    // is if you use a boundary condition helper:

    {
        Func g = BoundaryConditions::repeat_edge(f, 0, 100);
        count_partitions(g, 3);
    }

    // If you vectorize or otherwise split, then the last vector
    // (which gets shifted leftwards) is its own partition. This
    // removes some clamping logic from the inner loop.

    {
        Func g;
        g(x) = f(x);
        g.vectorize(x, 8);
        count_partitions(g, 2);
    }

    // The slicing only applies to a single loop level - the
    // innermost one where it can be applied. So adding a boundary
    // condition to a 2D computation will produce 3 code paths, not 9.
    {
        Var y;
        Func g;
        g(x, y) = x + y;
        g.compute_root();
        Func h = BoundaryConditions::mirror_image(g, 0, 10, 0, 10);
        count_partitions(h, 3);
    }

    // If you split and also have a boundary condition, or have
    // multiple boundary conditions at play (e.g. because you're
    // blurring an inlined Func that uses a boundary condition), then
    // there are still only three partitions. The steady state is the
    // slice of the loop where *all* of the boundary conditions and
    // splitting logic simplify away.
    {
        Func g = BoundaryConditions::mirror_interior(f, 0, 10);
        Func h;
        Param<int> t1, t2;
        h(x) = g(x-1) + g(x+1);
        h.vectorize(x, 8);
        count_partitions(h, 3);
    }

    // You can manually control the splitting behavior using the
    // 'likely' intrinsic. When used on one side of a select, min,
    // max, or clamp, it tags the select, min, max, or clamp as likely
    // to simplify to that expression in the steady state case, and
    // tries to solve for loop variable values for which this is true.
    {
        // So this code should produce a prologue that evaluates to sin(x), and
        // a steady state that evaluates to 1:
        Func g;
        g(x) = select(x < 10, sin(x), likely(1.0f));
        // There should be two partitions
        count_partitions(g, 2);
        // But only one should call sin
        count_sin_calls(g, 1);
    }

    {
        // This code should produce a prologue and epilogue that
        // evaluate sin(x), and a steady state that evaluates to 1:
        Func g;
        g(x) = select(x < 10 || x > 100, sin(x), likely(1.0f));
        // There should be three partitions
        count_partitions(g, 3);
        // With calls to sin in the prologue and epilogue.
        count_sin_calls(g, 2);
    }

    {

        // The max here should simplify to 10 in the steady state,
        // which means the select evaluates to 1.0f
        Func g;
        g(x) = select(min(x, likely(10)) > 0, 1.0f, sin(x));
        // There should be two partitions
        count_partitions(g, 2);
        // With a call to sin in the steady-state
        count_sin_calls(g, 1);
    }

    // As a specialize case, we treat clamped ramps as likely to
    // simplify to the clamped expression. This handles the many
    // existing cases where people have written their boundary
    // condition manually using clamp.
    {
        Func g;
        g(x) = f(clamp(x, 0, 10)); // treated as clamp(likely(x), 0, 10)
        g.vectorize(x, 8);
        count_partitions(g, 3);
    }

    // Using the likely intrinsic pulls some IR relating to the
    // condition outside of the loop. We'd better check that this
    // respects lets and doesn't do any combinatorial expansion. We'll
    // do this with a nasty comparison:
    {
        Func g;
        Var y;
        // Make some nasty expressions to compare to.
        Expr e[10];
        e[0] = y;
        for (int i = 1; i < 6; i++) {
            e[i] = e[i-1] * e[i-1] + y;
        }
        // Make a nasty condition that uses all of these.
        Expr nasty = cast<bool>(1);
        for (int i = 0; i < 6; i++) {
            nasty = nasty && (x*(i+1) < e[i]);
        }
        // Have an innermost loop over c to complicate things.
        Var c;
        g(c, x, y) = select(nasty, likely(10), c);

        // Check that it doesn't take the age of the world to compile,
        // and that it produces the right number of partitions.
        count_partitions(g, 2);

        // Note: The loops above would be larger, but the above code
        // sails through Halide then triggers exponential behavior
        // inside of LLVM :(
    }

    // The performance of this behavior is tested in
    // test/performance/boundary_conditions.cpp

    printf("Success!\n");
    return 0;
}
<commit_msg>Remove dubiously-constructed likely case that simplifies away<commit_after>#include "Halide.h"
#include <stdio.h>

using namespace Halide;
using namespace Halide::Internal;
using std::string;

// Count the number of stores to a given func, and the number of calls to sin
class Counter : public IRVisitor {
    string func;

    using IRVisitor::visit;

    void visit(const Store *op) {
        IRVisitor::visit(op);
        if (op->name == func) {
            store_count++;
        }
    }

    void visit(const Call *op) {
        IRVisitor::visit(op);
        if (op->name == "sin_f32") {
            sin_count++;
        }
    }

public:
    int store_count, sin_count;
    Counter(string f) : func(f), store_count(0), sin_count(0) {}
};

// Check that the number of calls to sin is correct.
class CheckSinCount : public IRMutator {
    int correct;
public:
    using IRMutator::mutate;

    Stmt mutate(Stmt s) {
        Counter c("");
        s.accept(&c);
        if (c.sin_count != correct) {
            printf("There were %d sin calls instead of %d\n", c.sin_count, correct);
            exit(-1);
        }
        return s;
    }

    CheckSinCount(int c) : correct(c) {}
};

// Check that the number of stores to a given func is correct
class CheckStoreCount : public IRMutator {
    string func;
    int correct;
public:
    using IRMutator::mutate;

    Stmt mutate(Stmt s) {
        Counter c(func);
        s.accept(&c);
        if (c.store_count != correct) {
            printf("There were %d stores to %s instead of %d\n", c.store_count, func.c_str(), correct);
            exit(-1);
        }
        return s;
    }

    CheckStoreCount(string f, int c) : func(f), correct(c) {}
};

void count_partitions(Func g, int correct) {
    g.add_custom_lowering_pass(new CheckStoreCount(g.name(), correct));
    g.compile_jit();
}

void count_sin_calls(Func g, int correct) {
    g.add_custom_lowering_pass(new CheckSinCount(correct));
    g.compile_jit();
}

int main(int argc, char **argv) {
    Func f;
    Var x;
    f(x) = x;
    f.compute_root();

    // Halide will partition a loop into three pieces in a few
    // situations. The pieces are 1) a messy prologue, 2) a clean
    // steady state, and 3) a messy epilogue. One way to trigger this
    // is if you use a boundary condition helper:

    {
        Func g = BoundaryConditions::repeat_edge(f, 0, 100);
        count_partitions(g, 3);
    }

    // If you vectorize or otherwise split, then the last vector
    // (which gets shifted leftwards) is its own partition. This
    // removes some clamping logic from the inner loop.

    {
        Func g;
        g(x) = f(x);
        g.vectorize(x, 8);
        count_partitions(g, 2);
    }

    // The slicing only applies to a single loop level - the
    // innermost one where it can be applied. So adding a boundary
    // condition to a 2D computation will produce 3 code paths, not 9.
    {
        Var y;
        Func g;
        g(x, y) = x + y;
        g.compute_root();
        Func h = BoundaryConditions::mirror_image(g, 0, 10, 0, 10);
        count_partitions(h, 3);
    }

    // If you split and also have a boundary condition, or have
    // multiple boundary conditions at play (e.g. because you're
    // blurring an inlined Func that uses a boundary condition), then
    // there are still only three partitions. The steady state is the
    // slice of the loop where *all* of the boundary conditions and
    // splitting logic simplify away.
    {
        Func g = BoundaryConditions::mirror_interior(f, 0, 10);
        Func h;
        Param<int> t1, t2;
        h(x) = g(x-1) + g(x+1);
        h.vectorize(x, 8);
        count_partitions(h, 3);
    }

    // You can manually control the splitting behavior using the
    // 'likely' intrinsic. When used on one side of a select, min,
    // max, or clamp, it tags the select, min, max, or clamp as likely
    // to simplify to that expression in the steady state case, and
    // tries to solve for loop variable values for which this is true.
    {
        // So this code should produce a prologue that evaluates to sin(x), and
        // a steady state that evaluates to 1:
        Func g;
        g(x) = select(x < 10, sin(x), likely(1.0f));
        // There should be two partitions
        count_partitions(g, 2);
        // But only one should call sin
        count_sin_calls(g, 1);
    }

    {
        // This code should produce a prologue and epilogue that
        // evaluate sin(x), and a steady state that evaluates to 1:
        Func g;
        g(x) = select(x < 10 || x > 100, sin(x), likely(1.0f));
        // There should be three partitions
        count_partitions(g, 3);
        // With calls to sin in the prologue and epilogue.
        count_sin_calls(g, 2);
    }

    // As a specialize case, we treat clamped ramps as likely to
    // simplify to the clamped expression. This handles the many
    // existing cases where people have written their boundary
    // condition manually using clamp.
    {
        Func g;
        g(x) = f(clamp(x, 0, 10)); // treated as clamp(likely(x), 0, 10)
        g.vectorize(x, 8);
        count_partitions(g, 3);
    }

    // Using the likely intrinsic pulls some IR relating to the
    // condition outside of the loop. We'd better check that this
    // respects lets and doesn't do any combinatorial expansion. We'll
    // do this with a nasty comparison:
    {
        Func g;
        Var y;
        // Make some nasty expressions to compare to.
        Expr e[10];
        e[0] = y;
        for (int i = 1; i < 6; i++) {
            e[i] = e[i-1] * e[i-1] + y;
        }
        // Make a nasty condition that uses all of these.
        Expr nasty = cast<bool>(1);
        for (int i = 0; i < 6; i++) {
            nasty = nasty && (x*(i+1) < e[i]);
        }
        // Have an innermost loop over c to complicate things.
        Var c;
        g(c, x, y) = select(nasty, likely(10), c);

        // Check that it doesn't take the age of the world to compile,
        // and that it produces the right number of partitions.
        count_partitions(g, 2);

        // Note: The loops above would be larger, but the above code
        // sails through Halide then triggers exponential behavior
        // inside of LLVM :(
    }

    // The performance of this behavior is tested in
    // test/performance/boundary_conditions.cpp

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>#pragma once
#include "path.hpp"

struct stat;
namespace spn {
	using ToPathStr = To8Str;
	using PathCh = char;
	using PathStr = std::basic_string<PathCh>;
	using EnumCBD = std::function<void (const PathCh*, bool)>;

	struct Dir_depLinux {
		static std::string Getcwd();
		static void Chdir(ToPathStr path);
		static bool Chdir_nt(ToPathStr path);
		static void Mkdir(ToPathStr path, uint32_t mode);
		static void Chmod(ToPathStr path, uint32_t mode);
		static void Rmdir(ToPathStr path);
		static void Remove(ToPathStr path);
		static void Move(ToPathStr from, ToPathStr to);
		static void Copy(ToPathStr from, ToPathStr to);
		static void EnumEntry(ToPathStr path, EnumCBD cb);
		static FStatus Status(ToPathStr path);
		static FTime Filetime(ToPathStr path);
		static bool IsFile(ToPathStr path);
		static bool IsDirectory(ToPathStr path);

		static FStatus CreateFStatus(const struct stat& st);
		//! ファイルフラグ変換 (spinner -> linux)
		static uint32_t ConvertFlag_S2L(uint32_t flag);
		//! ファイルフラグ変換 (linux -> spinner)
		static uint32_t ConvertFlag_L2S(uint32_t flag);
		static PathStr GetCurrentDir();
		static void SetCurrentDir(const PathStr& path);
	};
	using DirDep = Dir_depLinux;
}
<commit_msg>dir_depLinux: XlibのヘッダのStatusマクロ定義に依る不具合の対処<commit_after>#pragma once
#include "path.hpp"

#ifdef Status
	#undef Status
#endif

struct stat;
namespace spn {
	using ToPathStr = To8Str;
	using PathCh = char;
	using PathStr = std::basic_string<PathCh>;
	using EnumCBD = std::function<void (const PathCh*, bool)>;

	struct Dir_depLinux {
		static std::string Getcwd();
		static void Chdir(ToPathStr path);
		static bool Chdir_nt(ToPathStr path);
		static void Mkdir(ToPathStr path, uint32_t mode);
		static void Chmod(ToPathStr path, uint32_t mode);
		static void Rmdir(ToPathStr path);
		static void Remove(ToPathStr path);
		static void Move(ToPathStr from, ToPathStr to);
		static void Copy(ToPathStr from, ToPathStr to);
		static void EnumEntry(ToPathStr path, EnumCBD cb);
		static FStatus Status(ToPathStr path);
		static FTime Filetime(ToPathStr path);
		static bool IsFile(ToPathStr path);
		static bool IsDirectory(ToPathStr path);

		static FStatus CreateFStatus(const struct stat& st);
		//! ファイルフラグ変換 (spinner -> linux)
		static uint32_t ConvertFlag_S2L(uint32_t flag);
		//! ファイルフラグ変換 (linux -> spinner)
		static uint32_t ConvertFlag_L2S(uint32_t flag);
		static PathStr GetCurrentDir();
		static void SetCurrentDir(const PathStr& path);
	};
	using DirDep = Dir_depLinux;
}
<|endoftext|>


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

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
  details.

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

======================================================================*/
#ifndef __itkMissingStructurePenalty_hxx
#define __itkMissingStructurePenalty_hxx

#include "itkMissingStructurePenalty.h"

namespace itk
{

/**
 * ******************* Constructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::MissingVolumeMeshPenalty()
{
  this->m_MappedMeshContainer = MappedMeshContainerType::New();
} // end Constructor

/**
 * ******************* Destructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet  >
::~MissingVolumeMeshPenalty()
{} // end Destructor

/**
 * *********************** Initialize *****************************
 */

template< class TFixedPointSet, class TMovingPointSet  >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::Initialize( void ) throw ( ExceptionObject )
{
  /** Call the initialize of the superclass. */
  //this->Superclass::Initialize();

  if( !this->m_Transform )
  {
    itkExceptionMacro( << "Transform is not present" );
  }

  if( !this->m_FixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer is not present" );
  }

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();
  this->m_MappedMeshContainer->Reserve( numberOfMeshes );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId )
  {
    FixedMeshConstPointer           fixedMesh      = this->m_FixedMeshContainer->ElementAt( meshId );
    MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int              numberOfPoints = fixedPoints->Size();

    typename MeshPointsContainerType::Pointer mappedPoints =  MeshPointsContainerType::New();
    mappedPoints->Reserve( numberOfPoints );

    typename FixedMeshType::Pointer mappedMesh = FixedMeshType::New();
    mappedMesh->SetPoints( mappedPoints );

    // mappedMesh was constructed with a Cellscontainer and CellDatacontainer of size 0.
    // We use a null pointer to set them to undefined, which is also the default behavior of the MeshReader.
    // "Write result mesh" checks the null pointer and writes a mesh with the remaining data filled in from the fixed mesh.
    mappedMesh->SetPointData( NULL );
    mappedMesh->SetCells( NULL );
    mappedMesh->SetCellData( NULL );

    this->m_MappedMeshContainer->SetElement( meshId, mappedMesh );

  }
} // end Initialize()

/**
 * ******************* GetValue *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
typename MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >::MeasureType
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValue( const TransformParametersType & parameters ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  MeasureType value = NumericTraits< MeasureType >::Zero;

  //OutputPointType fixedPoint;
  /** Get the current corresponding points. */

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  DerivativeType dummyDerivative;
  this->GetValueAndDerivative( parameters, value, dummyDerivative );

  return value;

} // end GetValue()

/**
 * ******************* GetDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetDerivative( const TransformParametersType & parameters,
  DerivativeType & derivative ) const
{
  /** When the derivative is calculated, all information for calculating
  * the metric value is available. It does not cost anything to calculate
  * the metric value now. Therefore, we have chosen to only implement the
  * GetValueAndDerivative(), supplying it with a dummy value variable.
  */
  MeasureType dummyvalue = NumericTraits< MeasureType >::Zero;
  this->GetValueAndDerivative( parameters, dummyvalue, derivative );

} // end GetDerivative()

/**
 * ******************* GetValueAndDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValueAndDerivative( const TransformParametersType & parameters,
  MeasureType & value, DerivativeType & derivative ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  value = NumericTraits< MeasureType >::Zero;

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  derivative = DerivativeType( this->GetNumberOfParameters() );
  derivative.Fill( NumericTraits< DerivativeValueType >::Zero );

  NonZeroJacobianIndicesType nzji( this->m_Transform->GetNumberOfNonZeroJacobianIndices() );
  TransformJacobianType      jacobian;

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();

  typedef typename FixedMeshType::PointType FixedMeshPointType;

  FixedMeshPointType zeroPoint = typename FixedMeshPointType::Point();
  zeroPoint.Fill( 0.0 );

  typename MeshPointsContainerType::Pointer pointCentroids = FixedMeshType::PointsContainer::New();
  pointCentroids->resize( numberOfMeshes, typename FixedMeshPointType::Point( zeroPoint ) );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId ) // loop over all meshes in container
  {
    const FixedMeshConstPointer           fixedMesh      = fixedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int                    numberOfPoints = fixedPoints->Size();

    const FixedMeshPointer           mappedMesh   = this->m_MappedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerPointer mappedPoints = mappedMesh->GetPoints();

    typename FixedMeshType::PointType &              pointCentroid = pointCentroids->ElementAt( meshId );
    typedef typename FixedMeshType::PointsContainer FixedMeshPointsContainerType;
    typename FixedMeshType::PointsContainer::Pointer derivPoints   = FixedMeshPointsContainerType::New();

    derivPoints->resize( numberOfPoints, typename FixedMeshPointType::Point( zeroPoint ) );

    MeshPointsContainerConstIteratorType fixedPointIt  = fixedPoints->Begin();
    MeshPointsContainerIteratorType      mappedPointIt = mappedPoints->Begin();
    MeshPointsContainerConstIteratorType fixedPointEnd = fixedPoints->End();

    for( ; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++mappedPointIt )
    {
      const OutputPointType mappedPoint = this->m_Transform->TransformPoint( fixedPointIt->Value() );
      mappedPointIt.Value()         = mappedPoint;
      pointCentroid.GetVnlVector() += mappedPoint.GetVnlVector();
    }
    pointCentroid.GetVnlVector() /= numberOfPoints;

    typename FixedMeshType::CellsContainerConstIterator cellBegin = fixedMesh->GetCells()->Begin();
    typename FixedMeshType::CellsContainerConstIterator cellEnd   = fixedMesh->GetCells()->End();

    typename CellInterfaceType::PointIdIterator beginpointer;
    float                              sumSignedVolume = 0.0;
    float                              sumAbsVolume    = 0.0;

    const int eps = 0.00001;

    for( ; cellBegin != cellEnd; ++cellBegin )
    {
      beginpointer = cellBegin->Value()->PointIdsBegin();
      float signedVolume;  // = vnl_determinant(fullMatrix.GetVnlMatrix());

      //const VectorType::const_pointer p1,p2,p3,p4;
      switch( FixedPointSetDimension )
      {
        case 2:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2 = mappedPoints->GetElement( p2Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer() );

          const int sign = ( signedVolume > eps ) - ( signedVolume < -eps );
          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * p2[ 1 ];
            derivPoints->at( p1Id )[ 1 ] -= sign * p2[ 0 ];
            derivPoints->at( p2Id )[ 0 ] -= sign * p1[ 1 ];
            derivPoints->at( p2Id )[ 1 ] += sign * p1[ 0 ];
          }

        }
        break;
        case 3:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2   = mappedPoints->GetElement( p2Id ) - pointCentroid;
          const FixedMeshPointIdentifier p3Id = *beginpointer;
          ++beginpointer;
          const VectorType p3 = mappedPoints->GetElement( p3Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer(), p3.GetDataPointer() );

          const int sign = ( ( signedVolume > eps ) - ( signedVolume < -eps ) );

          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * ( p2[ 1 ] * p3[ 2 ] - p2[ 2 ] * p3[ 1 ] );
            derivPoints->at( p1Id )[ 1 ] += sign * ( p2[ 2 ] * p3[ 0 ] - p2[ 0 ] * p3[ 2 ] );
            derivPoints->at( p1Id )[ 2 ] += sign * ( p2[ 0 ] * p3[ 1 ] - p2[ 1 ] * p3[ 0 ] );

            derivPoints->at( p2Id )[ 0 ] += sign * ( p1[ 2 ] * p3[ 1 ] - p1[ 1 ] * p3[ 2 ] );
            derivPoints->at( p2Id )[ 1 ] += sign * ( p1[ 0 ] * p3[ 2 ] - p1[ 2 ] * p3[ 0 ] );
            derivPoints->at( p2Id )[ 2 ] += sign * ( p1[ 1 ] * p3[ 0 ] - p1[ 0 ] * p3[ 1 ] );

            derivPoints->at( p3Id )[ 0 ] += sign * ( p1[ 1 ] * p2[ 2 ] - p1[ 2 ] * p2[ 1 ] );
            derivPoints->at( p3Id )[ 1 ] += sign * ( p1[ 2 ] * p2[ 0 ] - p1[ 0 ] * p2[ 2 ] );
            derivPoints->at( p3Id )[ 2 ] += sign * ( p1[ 0 ] * p2[ 1 ] - p1[ 1 ] * p2[ 0 ] );

          }
        }

        break;
        case 4:
        {
          const VectorConstPointer p1 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p2 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p3 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p4 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          signedVolume = vnl_determinant( p1, p2, p3, p4 );
        }
        break;
        default:
          std::cout << "no dimensions higher than 4"  << std::endl;
      }

      sumSignedVolume +=  signedVolume;
      sumAbsVolume    += abs( signedVolume );
    }

    /** Create iterators. */
    fixedPointIt = fixedPoints->Begin();
    unsigned int pointIndex;
    /** Loop over points. */
    for( pointIndex = 0; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++pointIndex )
    {
      /** Get the TransformJacobian dT/dmu. */
      this->m_Transform->GetJacobian( fixedPointIt.Value(), jacobian, nzji );
      if( nzji.size() == this->GetNumberOfParameters() )
      {
        /** Loop over all Jacobians. */
        derivative += derivPoints->at( pointIndex ).GetVnlVector() * jacobian; //* sumAbsVolumeEps;
      }
      else
      {
        /** Only pick the nonzero Jacobians. */
        for( unsigned int i = 0; i < nzji.size(); ++i )
        {
          const unsigned int index  = nzji[ i ];
          VnlVectorType      column = jacobian.get_column( i );
          derivative[ index ] += dot_product( derivPoints->at( pointIndex ).GetVnlVector(), column ); // *sumAbsVolumeEps;
        }
      }

    }   // end loop over all corresponding points

    /** Check if enough samples were valid. */

    /** Copy the measure to value. */
    value += sumAbsVolume;

  } // end loop over all meshes in container
} // end GetValueAndDerivative()

/**
 * ******************* SubVector *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::SubVector( const VectorType & fullVector,  SubVectorType & subVector, const unsigned int leaveOutIndex )  const
{
  //SubVectorType subVector = SubVectorType::Vector();

  typename VectorType::ConstIterator    fullVectorIt  = fullVector.Begin();
  typename VectorType::ConstIterator    fullVectorEnd = fullVector.End();
  typename SubVectorType::Iterator      subVectorIt   = subVector.Begin();
  typename SubVectorType::ConstIterator subVectorEnd  = subVector.End();
  unsigned int                 fullIndex     = 0;
  for( ; subVectorIt != subVectorEnd; ++fullVectorIt, ++subVectorIt, ++fullIndex )
  {
    if( fullIndex == leaveOutIndex )
    {
      ++fullVectorIt;
    }
    *subVectorIt = *fullVectorIt;
  }

} // end SubVector()

} // end itk namespace

#endif // end #ifndef __itkMissingStructurePenalty_hxx

<commit_msg>BUG: int should be float<commit_after>/*======================================================================

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
  details.

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

======================================================================*/
#ifndef __itkMissingStructurePenalty_hxx
#define __itkMissingStructurePenalty_hxx

#include "itkMissingStructurePenalty.h"

namespace itk
{

/**
 * ******************* Constructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::MissingVolumeMeshPenalty()
{
  this->m_MappedMeshContainer = MappedMeshContainerType::New();
} // end Constructor

/**
 * ******************* Destructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet  >
::~MissingVolumeMeshPenalty()
{} // end Destructor

/**
 * *********************** Initialize *****************************
 */

template< class TFixedPointSet, class TMovingPointSet  >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::Initialize( void ) throw ( ExceptionObject )
{
  /** Call the initialize of the superclass. */
  //this->Superclass::Initialize();

  if( !this->m_Transform )
  {
    itkExceptionMacro( << "Transform is not present" );
  }

  if( !this->m_FixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer is not present" );
  }

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();
  this->m_MappedMeshContainer->Reserve( numberOfMeshes );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId )
  {
    FixedMeshConstPointer           fixedMesh      = this->m_FixedMeshContainer->ElementAt( meshId );
    MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int              numberOfPoints = fixedPoints->Size();

    typename MeshPointsContainerType::Pointer mappedPoints =  MeshPointsContainerType::New();
    mappedPoints->Reserve( numberOfPoints );

    typename FixedMeshType::Pointer mappedMesh = FixedMeshType::New();
    mappedMesh->SetPoints( mappedPoints );

    // mappedMesh was constructed with a Cellscontainer and CellDatacontainer of size 0.
    // We use a null pointer to set them to undefined, which is also the default behavior of the MeshReader.
    // "Write result mesh" checks the null pointer and writes a mesh with the remaining data filled in from the fixed mesh.
    mappedMesh->SetPointData( NULL );
    mappedMesh->SetCells( NULL );
    mappedMesh->SetCellData( NULL );

    this->m_MappedMeshContainer->SetElement( meshId, mappedMesh );

  }
} // end Initialize()

/**
 * ******************* GetValue *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
typename MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >::MeasureType
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValue( const TransformParametersType & parameters ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  MeasureType value = NumericTraits< MeasureType >::Zero;

  //OutputPointType fixedPoint;
  /** Get the current corresponding points. */

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  DerivativeType dummyDerivative;
  this->GetValueAndDerivative( parameters, value, dummyDerivative );

  return value;

} // end GetValue()

/**
 * ******************* GetDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetDerivative( const TransformParametersType & parameters,
  DerivativeType & derivative ) const
{
  /** When the derivative is calculated, all information for calculating
  * the metric value is available. It does not cost anything to calculate
  * the metric value now. Therefore, we have chosen to only implement the
  * GetValueAndDerivative(), supplying it with a dummy value variable.
  */
  MeasureType dummyvalue = NumericTraits< MeasureType >::Zero;
  this->GetValueAndDerivative( parameters, dummyvalue, derivative );

} // end GetDerivative()

/**
 * ******************* GetValueAndDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValueAndDerivative( const TransformParametersType & parameters,
  MeasureType & value, DerivativeType & derivative ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  value = NumericTraits< MeasureType >::Zero;

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  derivative = DerivativeType( this->GetNumberOfParameters() );
  derivative.Fill( NumericTraits< DerivativeValueType >::Zero );

  NonZeroJacobianIndicesType nzji( this->m_Transform->GetNumberOfNonZeroJacobianIndices() );
  TransformJacobianType      jacobian;

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();

  typedef typename FixedMeshType::PointType FixedMeshPointType;

  FixedMeshPointType zeroPoint = typename FixedMeshPointType::Point();
  zeroPoint.Fill( 0.0 );

  typename MeshPointsContainerType::Pointer pointCentroids = FixedMeshType::PointsContainer::New();
  pointCentroids->resize( numberOfMeshes, typename FixedMeshPointType::Point( zeroPoint ) );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId ) // loop over all meshes in container
  {
    const FixedMeshConstPointer           fixedMesh      = fixedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int                    numberOfPoints = fixedPoints->Size();

    const FixedMeshPointer           mappedMesh   = this->m_MappedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerPointer mappedPoints = mappedMesh->GetPoints();

    typename FixedMeshType::PointType &              pointCentroid = pointCentroids->ElementAt( meshId );
    typedef typename FixedMeshType::PointsContainer FixedMeshPointsContainerType;
    typename FixedMeshType::PointsContainer::Pointer derivPoints   = FixedMeshPointsContainerType::New();

    derivPoints->resize( numberOfPoints, typename FixedMeshPointType::Point( zeroPoint ) );

    MeshPointsContainerConstIteratorType fixedPointIt  = fixedPoints->Begin();
    MeshPointsContainerIteratorType      mappedPointIt = mappedPoints->Begin();
    MeshPointsContainerConstIteratorType fixedPointEnd = fixedPoints->End();

    for( ; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++mappedPointIt )
    {
      const OutputPointType mappedPoint = this->m_Transform->TransformPoint( fixedPointIt->Value() );
      mappedPointIt.Value()         = mappedPoint;
      pointCentroid.GetVnlVector() += mappedPoint.GetVnlVector();
    }
    pointCentroid.GetVnlVector() /= numberOfPoints;

    typename FixedMeshType::CellsContainerConstIterator cellBegin = fixedMesh->GetCells()->Begin();
    typename FixedMeshType::CellsContainerConstIterator cellEnd   = fixedMesh->GetCells()->End();

    typename CellInterfaceType::PointIdIterator beginpointer;
    float                              sumSignedVolume = 0.0;
    float                              sumAbsVolume    = 0.0;

    const float eps = 0.00001;

    for( ; cellBegin != cellEnd; ++cellBegin )
    {
      beginpointer = cellBegin->Value()->PointIdsBegin();
      float signedVolume;  // = vnl_determinant(fullMatrix.GetVnlMatrix());

      //const VectorType::const_pointer p1,p2,p3,p4;
      switch( FixedPointSetDimension )
      {
        case 2:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2 = mappedPoints->GetElement( p2Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer() );

          const int sign = ( signedVolume > eps ) - ( signedVolume < -eps );
          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * p2[ 1 ];
            derivPoints->at( p1Id )[ 1 ] -= sign * p2[ 0 ];
            derivPoints->at( p2Id )[ 0 ] -= sign * p1[ 1 ];
            derivPoints->at( p2Id )[ 1 ] += sign * p1[ 0 ];
          }

        }
        break;
        case 3:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2   = mappedPoints->GetElement( p2Id ) - pointCentroid;
          const FixedMeshPointIdentifier p3Id = *beginpointer;
          ++beginpointer;
          const VectorType p3 = mappedPoints->GetElement( p3Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer(), p3.GetDataPointer() );

          const int sign = ( ( signedVolume > eps ) - ( signedVolume < -eps ) );

          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * ( p2[ 1 ] * p3[ 2 ] - p2[ 2 ] * p3[ 1 ] );
            derivPoints->at( p1Id )[ 1 ] += sign * ( p2[ 2 ] * p3[ 0 ] - p2[ 0 ] * p3[ 2 ] );
            derivPoints->at( p1Id )[ 2 ] += sign * ( p2[ 0 ] * p3[ 1 ] - p2[ 1 ] * p3[ 0 ] );

            derivPoints->at( p2Id )[ 0 ] += sign * ( p1[ 2 ] * p3[ 1 ] - p1[ 1 ] * p3[ 2 ] );
            derivPoints->at( p2Id )[ 1 ] += sign * ( p1[ 0 ] * p3[ 2 ] - p1[ 2 ] * p3[ 0 ] );
            derivPoints->at( p2Id )[ 2 ] += sign * ( p1[ 1 ] * p3[ 0 ] - p1[ 0 ] * p3[ 1 ] );

            derivPoints->at( p3Id )[ 0 ] += sign * ( p1[ 1 ] * p2[ 2 ] - p1[ 2 ] * p2[ 1 ] );
            derivPoints->at( p3Id )[ 1 ] += sign * ( p1[ 2 ] * p2[ 0 ] - p1[ 0 ] * p2[ 2 ] );
            derivPoints->at( p3Id )[ 2 ] += sign * ( p1[ 0 ] * p2[ 1 ] - p1[ 1 ] * p2[ 0 ] );

          }
        }

        break;
        case 4:
        {
          const VectorConstPointer p1 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p2 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p3 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p4 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          signedVolume = vnl_determinant( p1, p2, p3, p4 );
        }
        break;
        default:
          std::cout << "no dimensions higher than 4"  << std::endl;
      }

      sumSignedVolume +=  signedVolume;
      sumAbsVolume    += abs( signedVolume );
    }

    /** Create iterators. */
    fixedPointIt = fixedPoints->Begin();
    unsigned int pointIndex;
    /** Loop over points. */
    for( pointIndex = 0; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++pointIndex )
    {
      /** Get the TransformJacobian dT/dmu. */
      this->m_Transform->GetJacobian( fixedPointIt.Value(), jacobian, nzji );
      if( nzji.size() == this->GetNumberOfParameters() )
      {
        /** Loop over all Jacobians. */
        derivative += derivPoints->at( pointIndex ).GetVnlVector() * jacobian; //* sumAbsVolumeEps;
      }
      else
      {
        /** Only pick the nonzero Jacobians. */
        for( unsigned int i = 0; i < nzji.size(); ++i )
        {
          const unsigned int index  = nzji[ i ];
          VnlVectorType      column = jacobian.get_column( i );
          derivative[ index ] += dot_product( derivPoints->at( pointIndex ).GetVnlVector(), column ); // *sumAbsVolumeEps;
        }
      }

    }   // end loop over all corresponding points

    /** Check if enough samples were valid. */

    /** Copy the measure to value. */
    value += sumAbsVolume;

  } // end loop over all meshes in container
} // end GetValueAndDerivative()

/**
 * ******************* SubVector *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::SubVector( const VectorType & fullVector,  SubVectorType & subVector, const unsigned int leaveOutIndex )  const
{
  //SubVectorType subVector = SubVectorType::Vector();

  typename VectorType::ConstIterator    fullVectorIt  = fullVector.Begin();
  typename VectorType::ConstIterator    fullVectorEnd = fullVector.End();
  typename SubVectorType::Iterator      subVectorIt   = subVector.Begin();
  typename SubVectorType::ConstIterator subVectorEnd  = subVector.End();
  unsigned int                 fullIndex     = 0;
  for( ; subVectorIt != subVectorEnd; ++fullVectorIt, ++subVectorIt, ++fullIndex )
  {
    if( fullIndex == leaveOutIndex )
    {
      ++fullVectorIt;
    }
    *subVectorIt = *fullVectorIt;
  }

} // end SubVector()

} // end itk namespace

#endif // end #ifndef __itkMissingStructurePenalty_hxx

<|endoftext|>


<commit_before>/* -*- mode:linux -*- */
/**
 * \file grid_world.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-10-08
 */

#include <iostream>

#include <stdlib.h>
#include <string.h>

#include "grid_state.h"
#include "grid_world.h"

using namespace std;

/**
 * Create a new GridWorld.
 */
GridWorld::GridWorld(const Heuristic *h, istream &s)
	: SearchDomain(h)
{
	char line[100];
	char c;

	s >> height;
	s >> width;

	obstacles = new bool[width * height];

	s >> line;
	if(strcmp(line, "Board:") != 0) {
		cerr << "Parse error: expected \"Board:\"" << endl;
		exit(EXIT_FAILURE);
	}
	c = s.get();		// new-line
	if (c != '\n') {
		cerr << endl << "Parse error: [" << c << "], h=" << h << endl;
		exit(EXIT_FAILURE);
	}
	for (int h = 0; h < height; h += 1) {
		for (int w = 0; w < width; w += 1) {
			c = s.get();
			if (c == '#')
				obstacles[width * h + w] = true;
			else
				obstacles[width * h + w] = false;
		}
		c = s.get();	// new-line
		if (c != '\n') {
			cerr << endl << "Parse error: [" << c << "], h=" << h << endl;
			exit(EXIT_FAILURE);
		}
	}

	// Cost (Unit/Life)
	s >> line;
	// Movement (Four-way/Eight-way)
	s >> line;

	s >> start_x;
	s >> start_y;
	s >> goal_x;
	s >> goal_y;
}

/**
 * Destructor.
 */
GridWorld::~GridWorld()
{
	delete obstacles;
}

/**
 * Get the initial state.
 */
State *GridWorld::initial_state(void)
{
	return new GridState(this, NULL, 0, start_x, start_y);
}

/**
 * Expand a gridstate.
 */
vector<const State*> *GridWorld::expand(const State *state) const
{
	const int cost = 1;
	const GridState *s;
	vector<const State*> *children;

	s = dynamic_cast<const GridState*>(state);
	children = new vector<const State*>();

	if (s->get_x() > 0 && !is_obstacle(s->get_x() + 1, s->get_y())) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x() + 1, s->get_y()));
	}
	if (s->get_x() < height - 1 && !is_obstacle(s->get_x() - 1, s->get_y())) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x() - 1, s->get_y()));
	}
	if (s->get_y() > 0 && !is_obstacle(s->get_x(), s->get_y() + 1)) {
			children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x(), s->get_y() + 1));
	}
	if (s->get_y() > width - 1 && !is_obstacle(s->get_x(), s->get_y() - 1)) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x(), s->get_y() - 1));
	}

	return children;
}

int GridWorld::get_goal_x(void) const
{
	return goal_x;
}

int GridWorld::get_goal_y(void) const
{
	return goal_y;
}

int GridWorld::get_width(void) const
{
	return width;
}

int GridWorld::get_height(void) const
{
	return height;
}

/**
 * Test if there is an obstacle at the given location.
 */
bool GridWorld::is_obstacle(int x, int y) const
{
	return obstacles[width * y + x];
}

/**
 * Prints the grid world to the given stream.
 */
void GridWorld::print(ostream &o) const
{
	o << height << " " << width << endl;
	o << "Board:" << endl;

	for (int h = 0; h < height; h += 1) {
		for (int w = 0; w < width; w += 1) {
			if (is_obstacle(w, h))
				o << "#";
			else
				o << " ";
		}
		o << endl;;
	}

	o << "Unit" << endl;
	o << "Four-way" << endl;
	o << start_x << " " << start_y << "\t" << goal_x << " " << goal_y << endl;
}
<commit_msg>Fix a delete error.<commit_after>/* -*- mode:linux -*- */
/**
 * \file grid_world.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-10-08
 */

#include <iostream>

#include <stdlib.h>
#include <string.h>

#include "grid_state.h"
#include "grid_world.h"

using namespace std;

/**
 * Create a new GridWorld.
 */
GridWorld::GridWorld(const Heuristic *h, istream &s)
	: SearchDomain(h)
{
	char line[100];
	char c;

	s >> height;
	s >> width;

	obstacles = new bool[width * height];

	s >> line;
	if(strcmp(line, "Board:") != 0) {
		cerr << "Parse error: expected \"Board:\"" << endl;
		exit(EXIT_FAILURE);
	}
	c = s.get();		// new-line
	if (c != '\n') {
		cerr << endl << "Parse error: [" << c << "], h=" << h << endl;
		exit(EXIT_FAILURE);
	}
	for (int h = 0; h < height; h += 1) {
		for (int w = 0; w < width; w += 1) {
			c = s.get();
			if (c == '#')
				obstacles[width * h + w] = true;
			else
				obstacles[width * h + w] = false;
		}
		c = s.get();	// new-line
		if (c != '\n') {
			cerr << endl << "Parse error: [" << c << "], h=" << h << endl;
			exit(EXIT_FAILURE);
		}
	}

	// Cost (Unit/Life)
	s >> line;
	// Movement (Four-way/Eight-way)
	s >> line;

	s >> start_x;
	s >> start_y;
	s >> goal_x;
	s >> goal_y;
}

/**
 * Destructor.
 */
GridWorld::~GridWorld()
{
	delete []obstacles;
}

/**
 * Get the initial state.
 */
State *GridWorld::initial_state(void)
{
	return new GridState(this, NULL, 0, start_x, start_y);
}

/**
 * Expand a gridstate.
 */
vector<const State*> *GridWorld::expand(const State *state) const
{
	const int cost = 1;
	const GridState *s;
	vector<const State*> *children;

	s = dynamic_cast<const GridState*>(state);
	children = new vector<const State*>();

	if (s->get_x() > 0 && !is_obstacle(s->get_x() + 1, s->get_y())) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x() + 1, s->get_y()));
	}
	if (s->get_x() < height - 1 && !is_obstacle(s->get_x() - 1, s->get_y())) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x() - 1, s->get_y()));
	}
	if (s->get_y() > 0 && !is_obstacle(s->get_x(), s->get_y() + 1)) {
			children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x(), s->get_y() + 1));
	}
	if (s->get_y() > width - 1 && !is_obstacle(s->get_x(), s->get_y() - 1)) {
		children->push_back(new GridState(this, state, s->get_g() + cost,
						  s->get_x(), s->get_y() - 1));
	}

	return children;
}

int GridWorld::get_goal_x(void) const
{
	return goal_x;
}

int GridWorld::get_goal_y(void) const
{
	return goal_y;
}

int GridWorld::get_width(void) const
{
	return width;
}

int GridWorld::get_height(void) const
{
	return height;
}

/**
 * Test if there is an obstacle at the given location.
 */
bool GridWorld::is_obstacle(int x, int y) const
{
	return obstacles[width * y + x];
}

/**
 * Prints the grid world to the given stream.
 */
void GridWorld::print(ostream &o) const
{
	o << height << " " << width << endl;
	o << "Board:" << endl;

	for (int h = 0; h < height; h += 1) {
		for (int w = 0; w < width; w += 1) {
			if (is_obstacle(w, h))
				o << "#";
			else
				o << " ";
		}
		o << endl;;
	}

	o << "Unit" << endl;
	o << "Four-way" << endl;
	o << start_x << " " << start_y << "\t" << goal_x << " " << goal_y << endl;
}
<|endoftext|>


<commit_before>#ifndef BST_HPP
#define BST_HPP
#include "BSTNode.hpp"
#include "BSTIterator.hpp"
#include <utility> // for std::pair

template<typename Data>
class BST {

protected:

  /** Pointer to the root of this BST, or nullptr if the BST is empty */
  BSTNode<Data>* root;

  /** Number of Data items stored in this BST. */
  unsigned int isize;

public:

  /** iterator is an aliased typename for BSTIterator<Data>. */
  typedef BSTIterator<Data> iterator;

  /** Default constructor.
      Initialize an empty BST.
   */
  BST() : root(nullptr), isize(0)
  {
  }

  /** Default destructor.
   *  It is virtual, to allow appropriate destruction of subclass objects.
   *  Delete every node in this BST.
   */ // TODO
  virtual ~BST()
  {
    delete (*this)->root;
  }

  /** Insert a Data item in the BST.
   *  Return a pair, with the pair's first member set to an
   *  iterator pointing to either the newly inserted element
   *  or to the equivalent element already in the set.
   *  The pair's second element is set to true
   *  if a new element was inserted or false if an
   *  equivalent element already existed.
   */ // TODO
  virtual std::pair<iterator,bool> insert(const Data& item)
  {
    bool inserted;

    ++isize;
    return std::pair<a,inserted>;
  }

  /** Find a Data item in the BST.
   *  Return an iterator pointing to the item, or the end
   *  iterator if the item is not in the BST.
   */ // TODO
  iterator find(const Data& item) const
  {
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    if (iter->curr->data == item)
      return iter;
    else
    {
      if
  }

  /** Return the number of items currently in the BST.
   */ // TODO
  unsigned int size() const
  {
    return isize;
  }

  /** Remove all elements from this BST, and destroy them,
   *  leaving this BST with a size of 0.
   */ // TODO
  void clear()
  {

    isize = 0;
  }

  /** Return true if the BST is empty, else false.
   */ // TODO
  bool empty() const
  {
    return ( isize == 0 );
  }

  /** Return an iterator pointing to the first item in the BST.
   */ // TODO
  iterator begin() const
  {
    BSTNode<Data> temp = ( (*this)->root );
    while (temp->left)
      temp = temp->left;

    return new BSTIterator<Data>(temp);
  }

  /** Return an iterator pointing past the last item in the BST.
   */
  iterator end() const
  {
    return typename BST<Data>::iterator(nullptr);
  }

 };

#endif //BST_HPP
<commit_msg>not enough changes to make a commit message worthwhile<commit_after>#ifndef BST_HPP
#define BST_HPP
#include "BSTNode.hpp"
#include "BSTIterator.hpp"
#include <utility> // for std::pair

template<typename Data>
class BST {

protected:

  /** Pointer to the root of this BST, or nullptr if the BST is empty */
  BSTNode<Data>* root;

  /** Number of Data items stored in this BST. */
  unsigned int isize;

public:

  /** iterator is an aliased typename for BSTIterator<Data>. */
  typedef BSTIterator<Data> iterator;

  /** Default constructor.
      Initialize an empty BST.
   */
  BST() : root(nullptr), isize(0)
  {
  }

  /** Default destructor.
   *  It is virtual, to allow appropriate destruction of subclass objects.
   *  Delete every node in this BST.
   */ // TODO
  virtual ~BST()
  {
    delete (*this)->root;
  }

  /** Insert a Data item in the BST.
   *  Return a pair, with the pair's first member set to an
   *  iterator pointing to either the newly inserted element
   *  or to the equivalent element already in the set.
   *  The pair's second element is set to true
   *  if a new element was inserted or false if an
   *  equivalent element already existed.
   */ // TODO
  virtual std::pair<iterator,bool> insert(const Data& item)
  {
    bool inserted;

    ++isize;
    return std::pair<a,inserted>;
  }

  /** Find a Data item in the BST.
   *  Return an iterator pointing to the item, or the end
   *  iterator if the item is not in the BST.
   */ // TODO
  iterator find(const Data& item) const
  {
    BSTIterator<Data> iter = new BSTIterator<Data>((*this)->root);
    if (item == iter->curr->data)
      return iter;
    else
    {
      if (item < iter->curr->data)

  }

  /** Return the number of items currently in the BST.
   */ // TODO
  unsigned int size() const
  {
    return isize;
  }

  /** Remove all elements from this BST, and destroy them,
   *  leaving this BST with a size of 0.
   */ // TODO
  void clear()
  {

    isize = 0;
  }

  /** Return true if the BST is empty, else false.
   */ // TODO
  bool empty() const
  {
    return ( isize == 0 );
  }

  /** Return an iterator pointing to the first item in the BST.
   */ // TODO
  iterator begin() const
  {
    BSTNode<Data> temp = ( (*this)->root );
    while (temp->left)
      temp = temp->left;

    return new BSTIterator<Data>(temp);
  }

  /** Return an iterator pointing past the last item in the BST.
   */
  iterator end() const
  {
    return typename BST<Data>::iterator(nullptr);
  }

 };

#endif //BST_HPP
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Sk2DPathEffect.h"
#include "SkBlitter.h"
#include "SkPath.h"
#include "SkScan.h"

class Sk2DPathEffectBlitter : public SkBlitter {
public:
    Sk2DPathEffectBlitter(Sk2DPathEffect* pe, SkPath* dst)
        : fPE(pe), fDst(dst)
    {}
    virtual void blitH(int x, int y, int count)
    {
        fPE->nextSpan(x, y, count, fDst);
    }
private:
    Sk2DPathEffect* fPE;
    SkPath*         fDst;
};

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

Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat)
{
    mat.invert(&fInverse);
}

bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
{
    Sk2DPathEffectBlitter   blitter(this, dst);
    SkPath                  tmp;
    SkIRect                 ir;

    src.transform(fInverse, &tmp);
    tmp.getBounds().round(&ir);
    if (!ir.isEmpty()) {
        // need to pass a clip to fillpath, required for inverse filltypes,
        // even though those do not make sense for this patheffect
        SkRegion clip(ir);

        this->begin(ir, dst);
        SkScan::FillPath(tmp, clip, &blitter);
        this->end(dst);
    }
    return true;
}

void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path)
{
    const SkMatrix& mat = this->getMatrix();
    SkPoint src, dst;

    src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
    do {
        mat.mapPoints(&dst, &src, 1);
        this->next(dst, x++, y, path);
        src.fX += SK_Scalar1;
    } while (--count > 0);
}

void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) {}
void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {}
void Sk2DPathEffect::end(SkPath* dst) {}

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

void Sk2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
{
    char storage[SkMatrix::kMaxFlattenSize];
    uint32_t size = fMatrix.flatten(storage);
    buffer.write32(size);
    buffer.write(storage, size);
}

Sk2DPathEffect::Sk2DPathEffect(SkFlattenableReadBuffer& buffer)
{
    char storage[SkMatrix::kMaxFlattenSize];
    uint32_t size = buffer.readS32();
    SkASSERT(size <= sizeof(storage));
    buffer.read(storage, size);
    fMatrix.unflatten(storage);
    fMatrix.invert(&fInverse);
}

SkFlattenable::Factory Sk2DPathEffect::getFactory()
{
    return CreateProc;
}

SkFlattenable* Sk2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
{
    return SkNEW_ARGS(Sk2DPathEffect, (buffer));
}

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

SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
    : INHERITED(m), fPath(p) {
}

SkPath2DPathEffect::SkPath2DPathEffect(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    fPath.unflatten(buffer);
}

SkFlattenable* SkPath2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
    return SkNEW_ARGS(SkPath2DPathEffect, (buffer));
}

void SkPath2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
    this->INHERITED::flatten(buffer);
    fPath.flatten(buffer);
}

SkFlattenable::Factory SkPath2DPathEffect::getFactory() {
    return CreateProc;
}

void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {
    dst->addPath(fPath, loc.fX, loc.fY);
}

static SkFlattenable::Registrar gReg("SkPath2DPathEffect",
                                     SkPath2DPathEffect::CreateProc);

<commit_msg>style cleanup<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Sk2DPathEffect.h"
#include "SkBlitter.h"
#include "SkPath.h"
#include "SkScan.h"

class Sk2DPathEffectBlitter : public SkBlitter {
public:
    Sk2DPathEffectBlitter(Sk2DPathEffect* pe, SkPath* dst)
        : fPE(pe), fDst(dst) {}

    virtual void blitH(int x, int y, int count) {
        fPE->nextSpan(x, y, count, fDst);
    }
private:
    Sk2DPathEffect* fPE;
    SkPath*         fDst;
};

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

Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
    mat.invert(&fInverse);
}

bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
    Sk2DPathEffectBlitter   blitter(this, dst);
    SkPath                  tmp;
    SkIRect                 ir;

    src.transform(fInverse, &tmp);
    tmp.getBounds().round(&ir);
    if (!ir.isEmpty()) {
        // need to pass a clip to fillpath, required for inverse filltypes,
        // even though those do not make sense for this patheffect
        SkRegion clip(ir);

        this->begin(ir, dst);
        SkScan::FillPath(tmp, clip, &blitter);
        this->end(dst);
    }
    return true;
}

void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) {
    const SkMatrix& mat = this->getMatrix();
    SkPoint src, dst;

    src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
    do {
        mat.mapPoints(&dst, &src, 1);
        this->next(dst, x++, y, path);
        src.fX += SK_Scalar1;
    } while (--count > 0);
}

void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) {}
void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {}
void Sk2DPathEffect::end(SkPath* dst) {}

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

void Sk2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
    char storage[SkMatrix::kMaxFlattenSize];
    uint32_t size = fMatrix.flatten(storage);
    buffer.write32(size);
    buffer.write(storage, size);
}

Sk2DPathEffect::Sk2DPathEffect(SkFlattenableReadBuffer& buffer) {
    char storage[SkMatrix::kMaxFlattenSize];
    uint32_t size = buffer.readS32();
    SkASSERT(size <= sizeof(storage));
    buffer.read(storage, size);
    fMatrix.unflatten(storage);
    fMatrix.invert(&fInverse);
}

SkFlattenable::Factory Sk2DPathEffect::getFactory() {
    return CreateProc;
}

SkFlattenable* Sk2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
    return SkNEW_ARGS(Sk2DPathEffect, (buffer));
}

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

SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
    : INHERITED(m), fPath(p) {
}

SkPath2DPathEffect::SkPath2DPathEffect(SkFlattenableReadBuffer& buffer)
        : INHERITED(buffer) {
    fPath.unflatten(buffer);
}

SkFlattenable* SkPath2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
    return SkNEW_ARGS(SkPath2DPathEffect, (buffer));
}

void SkPath2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
    this->INHERITED::flatten(buffer);
    fPath.flatten(buffer);
}

SkFlattenable::Factory SkPath2DPathEffect::getFactory() {
    return CreateProc;
}

void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {
    dst->addPath(fPath, loc.fX, loc.fY);
}

static SkFlattenable::Registrar gReg("SkPath2DPathEffect",
                                     SkPath2DPathEffect::CreateProc);

<|endoftext|>