<commit_before>#pragma once

#include <map>
#include <memory>
#include <string>
#include <vector>
#include <sdbusplus/server.hpp>
#include "xyz/openbmc_project/Inventory/Manager/server.hpp"
#include "events.hpp"
#include "actions.hpp"

namespace phosphor
{
namespace inventory
{
namespace manager
{
namespace details
{

template <typename T>
using ServerObject = typename sdbusplus::server::object::object<T>;

using ManagerIface =
    sdbusplus::server::xyz::openbmc_project::Inventory::Manager;

/** @struct MakeInterface
 *  @brief Adapt an sdbusplus interface proxy.
 *
 *  Template instances are builder functions that create
 *  adapted sdbusplus interface proxy interface objects.
 *
 *  @tparam T - The type of the interface being adapted.
 */
template <typename T>
struct MakeInterface
{
    static auto make(sdbusplus::bus::bus& bus, const char* path)
    {
        using HolderType = holder::Holder<std::unique_ptr<T>>;
        return static_cast<std::unique_ptr<holder::Base>>(
                   HolderType::template make_unique<HolderType>(
                       std::forward<std::unique_ptr<T>>(
                           std::make_unique<T>(
                               std::forward<decltype(bus)>(bus),
                               std::forward<decltype(path)>(path)))));
    }
};
} // namespace details

/** @class Manager
 *  @brief OpenBMC inventory manager implementation.
 *
 *  A concrete implementation for the xyz.openbmc_project.Inventory.Manager
 *  DBus API.
 */
class Manager final :
    public details::ServerObject<details::ManagerIface>
{
    public:
        Manager() = delete;
        Manager(const Manager&) = delete;
        Manager& operator=(const Manager&) = delete;
        Manager(Manager&&) = default;
        Manager& operator=(Manager&&) = default;
        ~Manager() = default;

        /** @brief Construct an inventory manager.
         *
         *  @param[in] bus - An sdbusplus bus connection.
         *  @param[in] busname - The DBus busname to own.
         *  @param[in] root - The DBus path on which to implement
         *      an inventory manager.
         *  @param[in] iface - The DBus inventory interface to implement.
         */
        Manager(sdbusplus::bus::bus&&, const char*, const char*, const char*);

        using Object = std::map <
                       std::string, std::map <
                       std::string, sdbusplus::message::variant<std::string >>>;
        using EventInfo = std::tuple <
                          std::vector<details::EventBasePtr>,
                          std::vector<details::ActionBasePtr >>;

        /** @brief Start processing DBus messages. */
        void run() noexcept;

        /** @brief Provided for testing only. */
        void shutdown() noexcept;

        /** @brief sd_bus Notify method implementation callback. */
        void notify(std::string path, Object) override;

        /** @brief sd_bus signal callback. */
        void signal(sdbusplus::message::message&,
                    const details::DbusSignal& event,
                    const EventInfo& info);

        /** @brief Drop an object from DBus. */
        void destroyObject(const char*);

        /** @brief Invoke an sdbusplus server binding method.
         *
         *  Invoke the requested method with a reference to the requested
         *  sdbusplus server binding interface as a parameter.
         *
         *  @tparam T - The sdbusplus server binding interface type.
         *  @tparam U - The type of the sdbusplus server binding member.
         *  @tparam Args - Argument types of the binding member.
         *
         *  @param[in] path - The DBus path on which the method should
         *      be invoked.
         *  @param[in] interface - The DBus interface hosting the method.
         *  @param[in] member - Pointer to sdbusplus server binding member.
         *  @param[in] args - Arguments to forward to the binding member.
         *
         *  @returns - The return/value type of the binding method being
         *      called.
         */
        template<typename T, typename U, typename ...Args>
        decltype(auto) invokeMethod(const char* path, const char* interface,
                                    U&& member, Args&& ...args)
        {
            auto& holder = getInterface<std::unique_ptr<T>>(path, interface);
            auto& iface = *holder.get();
            return (iface.*member)(std::forward<Args>(args)...);
        }

        using SigArgs = std::vector <
                        std::unique_ptr <
                        std::tuple <
                        Manager*,
                        const details::DbusSignal*,
                        const EventInfo* >>>;
        using SigArg = SigArgs::value_type::element_type;

    private:
        using HolderPtr = std::unique_ptr<details::holder::Base>;
        using InterfaceComposite = std::map<std::string, HolderPtr>;
        using ObjectReferences = std::map<std::string, InterfaceComposite>;
        using Events = std::vector<EventInfo>;
        using MakerType = HolderPtr(*)(
                              sdbusplus::bus::bus&, const char*);
        using Makers = std::map<std::string, MakerType>;

        /** @brief Provides weak references to interface holders.
         *
         *  Common code for all types for the templated getInterface
         *  methods.
         *
         *  @param[in] path - The DBus path for which the interface
         *      holder instance should be provided.
         *  @param[in] interface - The DBus interface for which the
         *      holder instance should be provided.
         *
         *  @returns A weak reference to the holder instance.
         */
        details::holder::Base& getInterfaceHolder(
            const char*, const char*) const;
        details::holder::Base& getInterfaceHolder(
            const char*, const char*);

        /** @brief Provides weak references to interface holders.
         *
         *  @tparam T - The sdbusplus server binding interface type.
         *
         *  @param[in] path - The DBus path for which the interface
         *      should be provided.
         *  @param[in] interface - The DBus interface to obtain.
         *
         *  @returns A weak reference to the interface holder.
         */
        template<typename T>
        auto& getInterface(const char* path, const char* interface)
        {
            auto& holder = getInterfaceHolder(path, interface);
            return static_cast <
                   details::holder::Holder<T>& >(holder);
        }
        template<typename T>
        auto& getInterface(const char* path, const char* interface) const
        {
            auto& holder = getInterfaceHolder(path, interface);
            return static_cast <
                   const details::holder::Holder<T>& >(holder);
        }

        /** @brief Provided for testing only. */
        bool _shutdown;

        /** @brief Path prefix applied to any relative paths. */
        const char* _root;

        /** @brief A container of sdbusplus server interface references. */
        ObjectReferences _refs;

        /** @brief A container contexts for signal callbacks. */
        SigArgs _sigargs;

        /** @brief A container of sdbusplus signal matches.  */
        std::vector<sdbusplus::server::match::match> _matches;

        /** @brief Persistent sdbusplus DBus bus connection. */
        sdbusplus::bus::bus _bus;

        /** @brief sdbusplus org.freedesktop.DBus.ObjectManager reference. */
        sdbusplus::server::manager::manager _manager;

        /** @brief A container of pimgen generated events and responses.  */
        static const Events _events;

        /** @brief A container of pimgen generated factory methods.  */
        static const Makers _makers;
};

} // namespace manager
} // namespace inventory
} // namespace phosphor

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<commit_msg>Add volatile keyword on shutdown<commit_after>#pragma once

#include <map>
#include <memory>
#include <string>
#include <vector>
#include <sdbusplus/server.hpp>
#include "xyz/openbmc_project/Inventory/Manager/server.hpp"
#include "events.hpp"
#include "actions.hpp"

namespace phosphor
{
namespace inventory
{
namespace manager
{
namespace details
{

template <typename T>
using ServerObject = typename sdbusplus::server::object::object<T>;

using ManagerIface =
    sdbusplus::server::xyz::openbmc_project::Inventory::Manager;

/** @struct MakeInterface
 *  @brief Adapt an sdbusplus interface proxy.
 *
 *  Template instances are builder functions that create
 *  adapted sdbusplus interface proxy interface objects.
 *
 *  @tparam T - The type of the interface being adapted.
 */
template <typename T>
struct MakeInterface
{
    static auto make(sdbusplus::bus::bus& bus, const char* path)
    {
        using HolderType = holder::Holder<std::unique_ptr<T>>;
        return static_cast<std::unique_ptr<holder::Base>>(
                   HolderType::template make_unique<HolderType>(
                       std::forward<std::unique_ptr<T>>(
                           std::make_unique<T>(
                               std::forward<decltype(bus)>(bus),
                               std::forward<decltype(path)>(path)))));
    }
};
} // namespace details

/** @class Manager
 *  @brief OpenBMC inventory manager implementation.
 *
 *  A concrete implementation for the xyz.openbmc_project.Inventory.Manager
 *  DBus API.
 */
class Manager final :
    public details::ServerObject<details::ManagerIface>
{
    public:
        Manager() = delete;
        Manager(const Manager&) = delete;
        Manager& operator=(const Manager&) = delete;
        Manager(Manager&&) = default;
        Manager& operator=(Manager&&) = default;
        ~Manager() = default;

        /** @brief Construct an inventory manager.
         *
         *  @param[in] bus - An sdbusplus bus connection.
         *  @param[in] busname - The DBus busname to own.
         *  @param[in] root - The DBus path on which to implement
         *      an inventory manager.
         *  @param[in] iface - The DBus inventory interface to implement.
         */
        Manager(sdbusplus::bus::bus&&, const char*, const char*, const char*);

        using Object = std::map <
                       std::string, std::map <
                       std::string, sdbusplus::message::variant<std::string >>>;
        using EventInfo = std::tuple <
                          std::vector<details::EventBasePtr>,
                          std::vector<details::ActionBasePtr >>;

        /** @brief Start processing DBus messages. */
        void run() noexcept;

        /** @brief Provided for testing only. */
        void shutdown() noexcept;

        /** @brief sd_bus Notify method implementation callback. */
        void notify(std::string path, Object) override;

        /** @brief sd_bus signal callback. */
        void signal(sdbusplus::message::message&,
                    const details::DbusSignal& event,
                    const EventInfo& info);

        /** @brief Drop an object from DBus. */
        void destroyObject(const char*);

        /** @brief Invoke an sdbusplus server binding method.
         *
         *  Invoke the requested method with a reference to the requested
         *  sdbusplus server binding interface as a parameter.
         *
         *  @tparam T - The sdbusplus server binding interface type.
         *  @tparam U - The type of the sdbusplus server binding member.
         *  @tparam Args - Argument types of the binding member.
         *
         *  @param[in] path - The DBus path on which the method should
         *      be invoked.
         *  @param[in] interface - The DBus interface hosting the method.
         *  @param[in] member - Pointer to sdbusplus server binding member.
         *  @param[in] args - Arguments to forward to the binding member.
         *
         *  @returns - The return/value type of the binding method being
         *      called.
         */
        template<typename T, typename U, typename ...Args>
        decltype(auto) invokeMethod(const char* path, const char* interface,
                                    U&& member, Args&& ...args)
        {
            auto& holder = getInterface<std::unique_ptr<T>>(path, interface);
            auto& iface = *holder.get();
            return (iface.*member)(std::forward<Args>(args)...);
        }

        using SigArgs = std::vector <
                        std::unique_ptr <
                        std::tuple <
                        Manager*,
                        const details::DbusSignal*,
                        const EventInfo* >>>;
        using SigArg = SigArgs::value_type::element_type;

    private:
        using HolderPtr = std::unique_ptr<details::holder::Base>;
        using InterfaceComposite = std::map<std::string, HolderPtr>;
        using ObjectReferences = std::map<std::string, InterfaceComposite>;
        using Events = std::vector<EventInfo>;
        using MakerType = HolderPtr(*)(
                              sdbusplus::bus::bus&, const char*);
        using Makers = std::map<std::string, MakerType>;

        /** @brief Provides weak references to interface holders.
         *
         *  Common code for all types for the templated getInterface
         *  methods.
         *
         *  @param[in] path - The DBus path for which the interface
         *      holder instance should be provided.
         *  @param[in] interface - The DBus interface for which the
         *      holder instance should be provided.
         *
         *  @returns A weak reference to the holder instance.
         */
        details::holder::Base& getInterfaceHolder(
            const char*, const char*) const;
        details::holder::Base& getInterfaceHolder(
            const char*, const char*);

        /** @brief Provides weak references to interface holders.
         *
         *  @tparam T - The sdbusplus server binding interface type.
         *
         *  @param[in] path - The DBus path for which the interface
         *      should be provided.
         *  @param[in] interface - The DBus interface to obtain.
         *
         *  @returns A weak reference to the interface holder.
         */
        template<typename T>
        auto& getInterface(const char* path, const char* interface)
        {
            auto& holder = getInterfaceHolder(path, interface);
            return static_cast <
                   details::holder::Holder<T>& >(holder);
        }
        template<typename T>
        auto& getInterface(const char* path, const char* interface) const
        {
            auto& holder = getInterfaceHolder(path, interface);
            return static_cast <
                   const details::holder::Holder<T>& >(holder);
        }

        /** @brief Provided for testing only. */
        volatile bool _shutdown;

        /** @brief Path prefix applied to any relative paths. */
        const char* _root;

        /** @brief A container of sdbusplus server interface references. */
        ObjectReferences _refs;

        /** @brief A container contexts for signal callbacks. */
        SigArgs _sigargs;

        /** @brief A container of sdbusplus signal matches.  */
        std::vector<sdbusplus::server::match::match> _matches;

        /** @brief Persistent sdbusplus DBus bus connection. */
        sdbusplus::bus::bus _bus;

        /** @brief sdbusplus org.freedesktop.DBus.ObjectManager reference. */
        sdbusplus::server::manager::manager _manager;

        /** @brief A container of pimgen generated events and responses.  */
        static const Events _events;

        /** @brief A container of pimgen generated factory methods.  */
        static const Makers _makers;
};

} // namespace manager
} // namespace inventory
} // namespace phosphor

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <cstdio>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "../tools_common.h"
#include "./vpx_config.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/test_vectors.h"
#include "test/util.h"
#if CONFIG_WEBM_IO
#include "test/webm_video_source.h"
#endif
#include "vpx_mem/vpx_mem.h"

namespace {

enum DecodeMode {
  kSerialMode,
  kFrameParallMode
};

const int kDecodeMode = 0;
const int kThreads = 1;
const int kFileName = 2;

typedef std::tr1::tuple<int, int, const char*> DecodeParam;

class TestVectorTest : public ::libvpx_test::DecoderTest,
    public ::libvpx_test::CodecTestWithParam<DecodeParam> {
 protected:
  TestVectorTest()
      : DecoderTest(GET_PARAM(0)),
        md5_file_(NULL) {
  }

  virtual ~TestVectorTest() {
    if (md5_file_)
      fclose(md5_file_);
  }

  void OpenMD5File(const std::string& md5_file_name_) {
    md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_);
    ASSERT_TRUE(md5_file_ != NULL) << "Md5 file open failed. Filename: "
        << md5_file_name_;
  }

  virtual void DecompressedFrameHook(const vpx_image_t& img,
                                     const unsigned int frame_number) {
    ASSERT_TRUE(md5_file_ != NULL);
    char expected_md5[33];
    char junk[128];

    // Read correct md5 checksums.
    const int res = fscanf(md5_file_, "%s  %s", expected_md5, junk);
    ASSERT_NE(res, EOF) << "Read md5 data failed";
    expected_md5[32] = '\0';

    ::libvpx_test::MD5 md5_res;
    md5_res.Add(&img);
    const char *actual_md5 = md5_res.Get();

    // Check md5 match.
    ASSERT_STREQ(expected_md5, actual_md5)
        << "Md5 checksums don't match: frame number = " << frame_number;
  }

 private:
  FILE *md5_file_;
};

// This test runs through the whole set of test vectors, and decodes them.
// The md5 checksums are computed for each frame in the video file. If md5
// checksums match the correct md5 data, then the test is passed. Otherwise,
// the test failed.
TEST_P(TestVectorTest, MD5Match) {
  const DecodeParam input = GET_PARAM(1);
  const std::string filename = std::tr1::get<kFileName>(input);
  const int threads = std::tr1::get<kThreads>(input);
  const int mode = std::tr1::get<kDecodeMode>(input);
  libvpx_test::CompressedVideoSource *video = NULL;
  vpx_codec_flags_t flags = 0;
  vpx_codec_dec_cfg_t cfg = {0};
  char str[256];

  if (mode == kFrameParallMode) {
    flags |= VPX_CODEC_USE_FRAME_THREADING;
  }

  cfg.threads = threads;

  snprintf(str, sizeof(str) / sizeof(str[0]) - 1,
           "file: %s  mode: %s threads: %d",
           filename.c_str(), mode == 0 ? "Serial" : "Parallel", threads);
  SCOPED_TRACE(str);

  // Open compressed video file.
  if (filename.substr(filename.length() - 3, 3) == "ivf") {
    video = new libvpx_test::IVFVideoSource(filename);
  } else if (filename.substr(filename.length() - 4, 4) == "webm") {
#if CONFIG_WEBM_IO
    video = new libvpx_test::WebMVideoSource(filename);
#else
    fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
            filename.c_str());
    return;
#endif
  }
  video->Init();

  // Construct md5 file name.
  const std::string md5_filename = filename + ".md5";
  OpenMD5File(md5_filename);

  // Set decode config and flags.
  set_cfg(cfg);
  set_flags(flags);

  // Decode frame, and check the md5 matching.
  ASSERT_NO_FATAL_FAILURE(RunLoop(video, cfg));
  delete video;
}

// Test VP8 decode in serial mode with single thread.
// NOTE: VP8 only support serial mode.
VP8_INSTANTIATE_TEST_CASE(
    TestVectorTest,
    ::testing::Combine(
        ::testing::Values(0),  // Serial Mode.
        ::testing::Values(1),  // Single thread.
        ::testing::ValuesIn(libvpx_test::kVP8TestVectors,
                            libvpx_test::kVP8TestVectors +
                                libvpx_test::kNumVP8TestVectors)));

// Test VP9 decode in serial mode with single thread.
VP9_INSTANTIATE_TEST_CASE(
    TestVectorTest,
    ::testing::Combine(
        ::testing::Values(0),  // Serial Mode.
        ::testing::Values(1),  // Single thread.
        ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
                            libvpx_test::kVP9TestVectors +
                                libvpx_test::kNumVP9TestVectors)));

#if CONFIG_VP9_DECODER
// Test VP9 decode in frame parallel mode with different number of threads.
INSTANTIATE_TEST_CASE_P(
    VP9MultiThreadedFrameParallel, TestVectorTest,
    ::testing::Combine(
        ::testing::Values(
            static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)),
        ::testing::Combine(
            ::testing::Values(1),        // Frame Parallel mode.
            ::testing::Range(2, 9),      // With 2 ~ 8 threads.
            ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
                                libvpx_test::kVP9TestVectors +
                                    libvpx_test::kNumVP9TestVectors))));
#endif
}  // namespace
<commit_msg>Parall -> Parallel<commit_after>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <cstdio>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "../tools_common.h"
#include "./vpx_config.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/test_vectors.h"
#include "test/util.h"
#if CONFIG_WEBM_IO
#include "test/webm_video_source.h"
#endif
#include "vpx_mem/vpx_mem.h"

namespace {

enum DecodeMode {
  kSerialMode,
  kFrameParallelMode
};

const int kDecodeMode = 0;
const int kThreads = 1;
const int kFileName = 2;

typedef std::tr1::tuple<int, int, const char*> DecodeParam;

class TestVectorTest : public ::libvpx_test::DecoderTest,
    public ::libvpx_test::CodecTestWithParam<DecodeParam> {
 protected:
  TestVectorTest()
      : DecoderTest(GET_PARAM(0)),
        md5_file_(NULL) {
  }

  virtual ~TestVectorTest() {
    if (md5_file_)
      fclose(md5_file_);
  }

  void OpenMD5File(const std::string& md5_file_name_) {
    md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_);
    ASSERT_TRUE(md5_file_ != NULL) << "Md5 file open failed. Filename: "
        << md5_file_name_;
  }

  virtual void DecompressedFrameHook(const vpx_image_t& img,
                                     const unsigned int frame_number) {
    ASSERT_TRUE(md5_file_ != NULL);
    char expected_md5[33];
    char junk[128];

    // Read correct md5 checksums.
    const int res = fscanf(md5_file_, "%s  %s", expected_md5, junk);
    ASSERT_NE(res, EOF) << "Read md5 data failed";
    expected_md5[32] = '\0';

    ::libvpx_test::MD5 md5_res;
    md5_res.Add(&img);
    const char *actual_md5 = md5_res.Get();

    // Check md5 match.
    ASSERT_STREQ(expected_md5, actual_md5)
        << "Md5 checksums don't match: frame number = " << frame_number;
  }

 private:
  FILE *md5_file_;
};

// This test runs through the whole set of test vectors, and decodes them.
// The md5 checksums are computed for each frame in the video file. If md5
// checksums match the correct md5 data, then the test is passed. Otherwise,
// the test failed.
TEST_P(TestVectorTest, MD5Match) {
  const DecodeParam input = GET_PARAM(1);
  const std::string filename = std::tr1::get<kFileName>(input);
  const int threads = std::tr1::get<kThreads>(input);
  const int mode = std::tr1::get<kDecodeMode>(input);
  libvpx_test::CompressedVideoSource *video = NULL;
  vpx_codec_flags_t flags = 0;
  vpx_codec_dec_cfg_t cfg = {0};
  char str[256];

  if (mode == kFrameParallelMode) {
    flags |= VPX_CODEC_USE_FRAME_THREADING;
  }

  cfg.threads = threads;

  snprintf(str, sizeof(str) / sizeof(str[0]) - 1,
           "file: %s  mode: %s threads: %d",
           filename.c_str(), mode == 0 ? "Serial" : "Parallel", threads);
  SCOPED_TRACE(str);

  // Open compressed video file.
  if (filename.substr(filename.length() - 3, 3) == "ivf") {
    video = new libvpx_test::IVFVideoSource(filename);
  } else if (filename.substr(filename.length() - 4, 4) == "webm") {
#if CONFIG_WEBM_IO
    video = new libvpx_test::WebMVideoSource(filename);
#else
    fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
            filename.c_str());
    return;
#endif
  }
  video->Init();

  // Construct md5 file name.
  const std::string md5_filename = filename + ".md5";
  OpenMD5File(md5_filename);

  // Set decode config and flags.
  set_cfg(cfg);
  set_flags(flags);

  // Decode frame, and check the md5 matching.
  ASSERT_NO_FATAL_FAILURE(RunLoop(video, cfg));
  delete video;
}

// Test VP8 decode in serial mode with single thread.
// NOTE: VP8 only support serial mode.
VP8_INSTANTIATE_TEST_CASE(
    TestVectorTest,
    ::testing::Combine(
        ::testing::Values(0),  // Serial Mode.
        ::testing::Values(1),  // Single thread.
        ::testing::ValuesIn(libvpx_test::kVP8TestVectors,
                            libvpx_test::kVP8TestVectors +
                                libvpx_test::kNumVP8TestVectors)));

// Test VP9 decode in serial mode with single thread.
VP9_INSTANTIATE_TEST_CASE(
    TestVectorTest,
    ::testing::Combine(
        ::testing::Values(0),  // Serial Mode.
        ::testing::Values(1),  // Single thread.
        ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
                            libvpx_test::kVP9TestVectors +
                                libvpx_test::kNumVP9TestVectors)));

#if CONFIG_VP9_DECODER
// Test VP9 decode in frame parallel mode with different number of threads.
INSTANTIATE_TEST_CASE_P(
    VP9MultiThreadedFrameParallel, TestVectorTest,
    ::testing::Combine(
        ::testing::Values(
            static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)),
        ::testing::Combine(
            ::testing::Values(1),        // Frame Parallel mode.
            ::testing::Range(2, 9),      // With 2 ~ 8 threads.
            ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
                                libvpx_test::kVP9TestVectors +
                                    libvpx_test::kNumVP9TestVectors))));
#endif
}  // namespace
<|endoftext|>


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

/*! \file
\brief  This file contains main application program demoSpinStart
*/

#include "libapp/Usage.h"

#include "build/version.h"
#include "libio/stream.h"

#include "libga/ga.h"

#include <cassert>
#include <iostream>
#include <vector>

namespace
{
	/*! Spinor values associated with platonic solid vertices.
	 *
	 * Ref. "Relative Orientation" Horn, B. K.P.
	 */
	std::vector<ga::Spinor>
	spinValues
		()
	{
		std::vector<ga::Spinor> spins;

		std::vector<ga::Spinor> const identity
			{ ga::Spinor(1., ga::BiVector(0., 0., 0.))
			};

		std::vector<ga::Spinor> const cube
			{ ga::Spinor(0., ga::BiVector(1., 0., 0.))
			, ga::Spinor(0., ga::BiVector(0., 1., 0.))
			, ga::Spinor(0., ga::BiVector(0., 0., 1.))
			};

		double const bb(.5);
		std::vector<ga::Spinor> const tetrahedron
			{ ga::Spinor( bb, ga::BiVector( bb,  bb,  bb))
			, ga::Spinor( bb, ga::BiVector(-bb,  bb,  bb))
			, ga::Spinor( bb, ga::BiVector( bb, -bb,  bb))
			, ga::Spinor( bb, ga::BiVector( bb,  bb, -bb))
			, ga::Spinor( bb, ga::BiVector( bb, -bb, -bb))
			, ga::Spinor( bb, ga::BiVector(-bb,  bb, -bb))
			, ga::Spinor( bb, ga::BiVector(-bb, -bb,  bb))
			, ga::Spinor( bb, ga::BiVector(-bb, -bb, -bb))
			};

		double const cc(std::sqrt(.5));
		std::vector<ga::Spinor> const octahedron
			{ ga::Spinor( 0., ga::BiVector( 0.,  cc,  cc))
			, ga::Spinor( 0., ga::BiVector( 0.,  cc, -cc))
			, ga::Spinor( 0., ga::BiVector( cc,  0.,  cc))
			, ga::Spinor( 0., ga::BiVector( cc,  0., -cc))
			, ga::Spinor( 0., ga::BiVector( cc,  cc,  0.))
			, ga::Spinor( 0., ga::BiVector( cc, -cc,  0.))
			, ga::Spinor( cc, ga::BiVector( 0.,  0.,  cc))
			, ga::Spinor( cc, ga::BiVector( 0.,  0., -cc))
			, ga::Spinor( cc, ga::BiVector( 0.,  cc,  0.))
			, ga::Spinor( cc, ga::BiVector( 0., -cc,  0.))
			, ga::Spinor( cc, ga::BiVector( cc,  0.,  0.))
			, ga::Spinor( cc, ga::BiVector(-cc,  0.,  0.))
			};

		// 1 value
		spins.insert(spins.end(), identity.begin(), identity.end());
		// 4 values
		spins.insert(spins.end(), cube.begin(), cube.end());
		// 12 values
		spins.insert(spins.end(), tetrahedron.begin(), tetrahedron.end());
		// 24 values
		spins.insert(spins.end(), octahedron.begin(), octahedron.end());

		return spins;
	}

	//! Physical angles associated with spinors
	std::vector<ga::BiVector>
	physAnglesFor
		( std::vector<ga::Spinor> const & spins
		)
	{
		std::vector<ga::BiVector> bivs;
		bivs.reserve(spins.size());
		for (ga::Spinor const & spin : spins)
		{
			bivs.emplace_back(ga::spin::physicalAngleFrom(-spin));
		}
		return bivs;
	}
}

//! Display spinors proposed by Horn in "Relative Orientation [Revisisted]"
int
main
	( int const argc
	, char const * const * const argv
	)
{
	// check args
	app::Usage usage;
	usage.setSummary
		( "Display spinor sampling values (and bivAngle) proposed by Horn"
		);
//	usage.addArg("arg1", "description");
	// ...
	if (usage.argStatus(argc, argv) != app::Usage::Valid)
	{
		std::string const fname(argv[0]);
		io::err()
			<< std::endl << build::version::buildInfo(argv[0]) << std::endl
			<< usage.infoString(fname) << std::endl;
		return 1;
	}

	// parse input argument
//	int argnum(0);
//	std::string const arg1(argv[++argnum]);

	std::vector<ga::Spinor> const spins{ spinValues() };
	std::vector<ga::BiVector> const bivs{ physAnglesFor(spins) };
	size_t const numAtts{ spins.size() };
	assert(numAtts == bivs.size());
	for (size_t nn{0u} ; nn < numAtts ; ++nn)
	{
		ga::Spinor const & spin = spins[nn];
		ga::BiVector const & bivPos = bivs[nn];
		io::out()
			<< " " << dat::infoString(spin, "spin")
			<< " " << dat::infoString(bivPos, "bivPos")
			<< std::endl;
	}

	return 0;
}

<commit_msg>testro/demoSpinStart updated to use libga/groups<commit_after>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains main application program demoSpinStart
*/

#include "libapp/Usage.h"

#include "build/version.h"
#include "libio/stream.h"

#include "libga/ga.h"
#include "libga/groups.h"

#include <cassert>
#include <iostream>
#include <vector>

namespace
{
}

//! Display spinors proposed by Horn in "Relative Orientation [Revisisted]"
int
main
	( int const argc
	, char const * const * const argv
	)
{
	// check args
	app::Usage usage;
	usage.setSummary
		( "Display spinor sampling values (and bivAngle) proposed by Horn"
		);
//	usage.addArg("arg1", "description");
	// ...
	if (usage.argStatus(argc, argv) != app::Usage::Valid)
	{
		std::string const fname(argv[0]);
		io::err()
			<< std::endl << build::version::buildInfo(argv[0]) << std::endl
			<< usage.infoString(fname) << std::endl;
		return 1;
	}

	// parse input argument
//	int argnum(0);
//	std::string const arg1(argv[++argnum]);

	std::vector<ga::Spinor> const spins{ ga::groups::spreadOfSpinors() };
	std::vector<ga::BiVector> const bivs
		{ ga::groups::physicalAnglesFor(spins) };
	size_t const numAtts{ spins.size() };
	assert(numAtts == bivs.size());
	for (size_t nn{0u} ; nn < numAtts ; ++nn)
	{
		ga::Spinor const & spin = spins[nn];
		ga::BiVector const & bivPos = bivs[nn];
		ga::BiVector const pAng{ ga::spin::physicalAngleFrom(spin) };
		double const pMag{ ga::magnitude(pAng) };
		assert(pAng.nearlyEquals(bivPos));
		io::out()
			<< " " << dat::infoString(spin, "spin")
			<< " " << dat::infoString(bivPos, "bivPos")
		//	<< " " << dat::infoString(pAng, "pAng")
			<< " " << dat::infoString(pMag, "pMag")
			<< std::endl;
	}

	return 0;
}

<|endoftext|>


<commit_before>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickWindow)
{
    System::getSingleton().getDefaultGUIContext().injectMouseButtonClick(
        LeftButton);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 1);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksWindow)
{
    System::getSingleton().getDefaultGUIContext().injectMouseButtonClick(
        LeftButton);
    System::getSingleton().getDefaultGUIContext().injectMouseButtonClick(
        LeftButton);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 2);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickButton)
{
    //TODO: It doesn't work with injectMouseClick, but only with mouseDown + Up
    // Shouldn't it?
    System::getSingleton().getDefaultGUIContext().injectMousePosition(30.0f, 30.0f);
    System::getSingleton().getDefaultGUIContext().injectMouseButtonDown(
        LeftButton);
    System::getSingleton().getDefaultGUIContext().injectMouseButtonUp(
        LeftButton);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 0);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add tests for injecting keyboard input.<commit_after>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_editbox = WindowManager::getSingleton().createWindow("TaharezLook/Editbox");
        d_editbox->setPosition(UVector2(cegui_reldim(0.9f), cegui_reldim(0.9f)));
        d_editbox->setSize(USize(cegui_reldim(0.1f), cegui_reldim(0.1f)));

        d_window->addChild(d_editbox);
        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;
    Window* d_editbox;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

//----------------------------------------------------------------------------//
static inline GUIContext& getGUIContext()
{
    return System::getSingleton().getDefaultGUIContext();
}

static void doClick(float position_x, float position_y)
{
    getGUIContext().injectMousePosition(position_x, position_y);
    getGUIContext().injectMouseButtonDown(LeftButton);
    getGUIContext().injectMouseButtonUp(LeftButton);
}
//----------------------------------------------------------------------------//

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickOnWindow)
{
    // we check for both: a) being handled, b) have the expected final result
    BOOST_CHECK_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 1);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksOnWindow)
{
    BOOST_CHECK_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 2);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickOnButton)
{
    doClick(30.0f, 30.0f);

    BOOST_CHECK_EQUAL(d_windowHandledCount, 0);
    BOOST_CHECK_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_CASE(InsertSimpleText)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_CHECK_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithBackspace)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectKeyDown(Key::Backspace), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_CHECK_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithDelete)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_CHECK_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_CHECK_EQUAL(getGUIContext().injectKeyDown(Key::Delete), true);

    BOOST_CHECK_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#pragma once

#include "ThreadPool.hpp"

#include <htslib/sam.h>
#include <htslib/hts.h>

#include <boost/format.hpp>

#include <string>
#include <stdexcept>
#include <iostream>

class SamReader {
    public:
        SamReader(char const* path, char const* reference=NULL, ThreadPool* thread_pool=NULL)
            : _in(hts_open(path, "r"))
            , _required_flags(0)
            , _skip_flags(0)
        {
            using boost::format;
            if (!_in) {
                throw std::runtime_error(str(format(
                                "Failed to open input file %1%"
                                ) % path));
            }
            if (reference && *reference != '\0') {
                if (hts_set_opt(_in, CRAM_OPT_REFERENCE, reference) != 0) {
                    throw std::runtime_error(str(format(
                                    "Unable to use reference %1%"
                                    ) % reference));
                }
            }

            if (thread_pool) {
                if (hts_set_opt(_in, HTS_OPT_THREAD_POOL, thread_pool->pool()) != 0) {
                    throw std::runtime_error(str(format(
                                    "Failed to use threads to read %1%"
                                    ) % path));
                }
            }

            if (!(_hdr = sam_hdr_read(_in))) {
                throw std::runtime_error(str(format(
                                "Failed to read header from file %1%"
                                ) % path));
            }
        }

        ~SamReader() {
            if (_hdr) {
                bam_hdr_destroy(_hdr);
            }

            if (_in) {
                hts_close(_in);
            }
        }

        bam_hdr_t* header() const {
            return _hdr;
        }

        void required_flags(uint32_t flags) {
            _required_flags = flags;
        }

        void skip_flags(uint32_t flags) {
            _skip_flags = flags;
        }

        bool want(uint32_t flag) const {
            return (flag & _required_flags) == _required_flags
                && (flag & _skip_flags) == 0;
        }

        bool next(bam1_t* record) {
            while (sam_read1(_in, _hdr, record) > 0) {
                if (want(record->core.flag)) {
                    return true;
                }
            }
            return false;
        }

    private:
        htsFile* _in;
        bam_hdr_t* _hdr;
        uint32_t _required_flags;
        uint32_t _skip_flags;
};
<commit_msg>Test setting CRAM required fields<commit_after>#pragma once

#include "ThreadPool.hpp"

#include <htslib/sam.h>
#include <htslib/hts.h>

#include <boost/format.hpp>

#include <string>
#include <stdexcept>
#include <iostream>

class SamReader {
    public:
        SamReader(char const* path, char const* reference=NULL, ThreadPool* thread_pool=NULL)
            : _in(hts_open(path, "r"))
            , _required_flags(0)
            , _skip_flags(0)
        {
            using boost::format;
            if (!_in) {
                throw std::runtime_error(str(format(
                                "Failed to open input file %1%"
                                ) % path));
            }
            if (reference && *reference != '\0') {
                if (hts_set_opt(_in, CRAM_OPT_REFERENCE, reference) != 0) {
                    throw std::runtime_error(str(format(
                                    "Unable to use reference %1%"
                                    ) % reference));
                }
            }

            if (thread_pool) {
                if (hts_set_opt(_in, HTS_OPT_THREAD_POOL, thread_pool->pool()) != 0) {
                    throw std::runtime_error(str(format(
                                    "Failed to use threads to read %1%"
                                    ) % path));
                }
            }

            if (_in->format.format == cram) {
                // CRAM is flexible in terms of what it can decode.
                // Only ask for what we need
                if (hts_set_opt(_in, CRAM_OPT_REQUIRED_FIELDS,
                            SAM_FLAG | SAM_QNAME | SAM_RNAME | SAM_POS | SAM_CIGAR | SAM_TLEN | SAM_AUX | SAM_SEQ | SAM_QUAL) != 0) {
                    throw std::runtime_error(str(format("Unable to set CRAM reading options on %1%") % reference));
                }
            }

            if (!(_hdr = sam_hdr_read(_in))) {
                throw std::runtime_error(str(format(
                                "Failed to read header from file %1%"
                                ) % path));
            }
        }

        ~SamReader() {
            if (_hdr) {
                bam_hdr_destroy(_hdr);
            }

            if (_in) {
                hts_close(_in);
            }
        }

        bam_hdr_t* header() const {
            return _hdr;
        }

        void required_flags(uint32_t flags) {
            _required_flags = flags;
        }

        void skip_flags(uint32_t flags) {
            _skip_flags = flags;
        }

        bool want(uint32_t flag) const {
            return (flag & _required_flags) == _required_flags
                && (flag & _skip_flags) == 0;
        }

        bool next(bam1_t* record) {
            while (sam_read1(_in, _hdr, record) > 0) {
                if (want(record->core.flag)) {
                    return true;
                }
            }
            return false;
        }

    private:
        htsFile* _in;
        bam_hdr_t* _hdr;
        uint32_t _required_flags;
        uint32_t _skip_flags;
};
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2006-2007 Torsten Rahn <tackat@kde.org>
// Copyright 2007      Inge Wallin  <ingwa@kde.org>
// Copyright 2008,2009 Jens-Michael Hoffmann <jensmh@gmx.de>
//

#include "HttpDownloadManager.h"

#include <QList>
#include <QMap>
#include <QTimer>
#include <QNetworkAccessManager>

#include "DownloadPolicy.h"
#include "DownloadQueueSet.h"
#include "HttpJob.h"
#include "MarbleDebug.h"
#include "StoragePolicy.h"

using namespace Marble;

// Time before a failed download job is requeued in ms
const quint32 requeueTime = 60000;

class HttpDownloadManager::Private
{
  public:
    explicit Private( StoragePolicy *policy );
    ~Private();

    DownloadQueueSet *findQueues( const QString& hostName, const DownloadUsage usage );

    bool m_downloadEnabled;
    QTimer m_requeueTimer;
    /**
     * Contains per download policy a queue set containing of
     * - a queue where jobs are waiting for being activated (=downloaded)
     * - a queue containing currently being downloaded
     * - a queue for retries of failed downloads */
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> > m_queueSets;
    QMap<DownloadUsage, DownloadQueueSet *> m_defaultQueueSets;
    StoragePolicy *const m_storagePolicy;
    QNetworkAccessManager m_networkAccessManager;

};

HttpDownloadManager::Private::Private( StoragePolicy *policy )
    : m_downloadEnabled( true ), //enabled for now
      m_requeueTimer(),
      m_storagePolicy( policy ),
      m_networkAccessManager()
{
    // setup default download policy and associated queue set
    DownloadPolicy defaultBrowsePolicy;
    defaultBrowsePolicy.setMaximumConnections( 20 );
    m_defaultQueueSets[ DownloadBrowse ] = new DownloadQueueSet( defaultBrowsePolicy );
    DownloadPolicy defaultBulkDownloadPolicy;
    defaultBulkDownloadPolicy.setMaximumConnections( 2 );
    m_defaultQueueSets[ DownloadBulk ] = new DownloadQueueSet( defaultBulkDownloadPolicy );
}

HttpDownloadManager::Private::~Private()
{
    QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = m_defaultQueueSets.begin();
    QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = m_defaultQueueSets.end();
    for (; pos != end; ++pos )
        delete pos.value();
}

DownloadQueueSet *HttpDownloadManager::Private::findQueues( const QString& hostName,
                                                            const DownloadUsage usage )
{
    DownloadQueueSet * result = 0;
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator pos = m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator const end = m_queueSets.end();
    for (; pos != end; ++pos ) {
        if ( (*pos).first.matches( hostName, usage )) {
            result = (*pos).second;
            break;
        }
    }
    if ( !result ) {
        mDebug() << "No download policy found for" << hostName << usage
                 << ", using default policy.";
        result = m_defaultQueueSets[ usage ];
    }
    return result;
}

HttpDownloadManager::HttpDownloadManager( StoragePolicy *policy )
    : d( new Private( policy ) )
{
    d->m_requeueTimer.setInterval( requeueTime );
    connect( &d->m_requeueTimer, SIGNAL(timeout()), this, SLOT(requeue()) );
    connectDefaultQueueSets();
}

HttpDownloadManager::~HttpDownloadManager()
{
    delete d;
}

void HttpDownloadManager::setDownloadEnabled( const bool enable )
{
    d->m_downloadEnabled = enable;
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        pos->second->purgeJobs();
    }

}

void HttpDownloadManager::addDownloadPolicy( const DownloadPolicy& policy )
{
    if ( hasDownloadPolicy( policy ))
        return;
    DownloadQueueSet * const queueSet = new DownloadQueueSet( policy, this );
    connectQueueSet( queueSet );
    d->m_queueSets.append( QPair<DownloadPolicyKey, DownloadQueueSet *>
                           ( queueSet->downloadPolicy().key(), queueSet ));
}

void HttpDownloadManager::addJob( const QUrl& sourceUrl, const QString& destFileName,
                                  const QString &id, const DownloadUsage usage )
{
    if ( !d->m_downloadEnabled )
        return;

    DownloadQueueSet * const queueSet = d->findQueues( sourceUrl.host(), usage );
    if ( queueSet->canAcceptJob( sourceUrl, destFileName )) {
        HttpJob * const job = new HttpJob( sourceUrl, destFileName, id, &d->m_networkAccessManager );
        job->setUserAgentPluginId( "QNamNetworkPlugin" );
        job->setDownloadUsage( usage );
        queueSet->addJob( job );
    }
}

void HttpDownloadManager::finishJob( const QByteArray& data, const QString& destinationFileName,
                                     const QString& id )
{
    mDebug() << "emitting downloadComplete( QByteArray, " << id << ")";
    emit downloadComplete( data, id );
    if ( d->m_storagePolicy ) {
        const bool saved = d->m_storagePolicy->updateFile( destinationFileName, data );
        if ( saved ) {
            mDebug() << "emitting downloadComplete( " << destinationFileName << ", " << id << ")";
            emit downloadComplete( destinationFileName, id );
        } else {
            qWarning() << "Could not save:" << destinationFileName;
        }
    }
}

void HttpDownloadManager::requeue()
{
    d->m_requeueTimer.stop();

    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        (*pos).second->retryJobs();
    }
}

void HttpDownloadManager::startRetryTimer()
{
    if ( !d->m_requeueTimer.isActive() )
        d->m_requeueTimer.start();
}

void HttpDownloadManager::connectDefaultQueueSets()
{
    QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = d->m_defaultQueueSets.begin();
    QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = d->m_defaultQueueSets.end();
    for (; pos != end; ++pos )
        connectQueueSet( pos.value() );
}

void HttpDownloadManager::connectQueueSet( DownloadQueueSet * queueSet )
{
    connect( queueSet, SIGNAL(jobFinished(QByteArray,QString,QString)),
             SLOT(finishJob(QByteArray,QString,QString)));
    connect( queueSet, SIGNAL(jobRetry()), SLOT(startRetryTimer()));
    connect( queueSet, SIGNAL(jobRedirected(QUrl,QString,QString,DownloadUsage)),
             SLOT(addJob(QUrl,QString,QString,DownloadUsage)));
    // relay jobAdded/jobRemoved signals (interesting for progress bar)
    connect( queueSet, SIGNAL(jobAdded()), SIGNAL(jobAdded()));
    connect( queueSet, SIGNAL(jobRemoved()), SIGNAL(jobRemoved()));
    connect( queueSet, SIGNAL(progressChanged(int,int)), SIGNAL(progressChanged(int,int)) );
}

bool HttpDownloadManager::hasDownloadPolicy( const DownloadPolicy& policy ) const
{
    bool found = false;
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        if ( (*pos).second->downloadPolicy() == policy ) {
            found = true;
            break;
        }
    }
    return found;
}

#include "HttpDownloadManager.moc"
<commit_msg>remove redundant attribute<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2006-2007 Torsten Rahn <tackat@kde.org>
// Copyright 2007      Inge Wallin  <ingwa@kde.org>
// Copyright 2008,2009 Jens-Michael Hoffmann <jensmh@gmx.de>
//

#include "HttpDownloadManager.h"

#include <QList>
#include <QMap>
#include <QTimer>
#include <QNetworkAccessManager>

#include "DownloadPolicy.h"
#include "DownloadQueueSet.h"
#include "HttpJob.h"
#include "MarbleDebug.h"
#include "StoragePolicy.h"

using namespace Marble;

// Time before a failed download job is requeued in ms
const quint32 requeueTime = 60000;

class HttpDownloadManager::Private
{
  public:
    explicit Private( StoragePolicy *policy );
    ~Private();

    DownloadQueueSet *findQueues( const QString& hostName, const DownloadUsage usage );

    QTimer m_requeueTimer;
    /**
     * Contains per download policy a queue set containing of
     * - a queue where jobs are waiting for being activated (=downloaded)
     * - a queue containing currently being downloaded
     * - a queue for retries of failed downloads */
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> > m_queueSets;
    QMap<DownloadUsage, DownloadQueueSet *> m_defaultQueueSets;
    StoragePolicy *const m_storagePolicy;
    QNetworkAccessManager m_networkAccessManager;

};

HttpDownloadManager::Private::Private( StoragePolicy *policy )
    : m_requeueTimer(),
      m_storagePolicy( policy ),
      m_networkAccessManager()
{
    // setup default download policy and associated queue set
    DownloadPolicy defaultBrowsePolicy;
    defaultBrowsePolicy.setMaximumConnections( 20 );
    m_defaultQueueSets[ DownloadBrowse ] = new DownloadQueueSet( defaultBrowsePolicy );
    DownloadPolicy defaultBulkDownloadPolicy;
    defaultBulkDownloadPolicy.setMaximumConnections( 2 );
    m_defaultQueueSets[ DownloadBulk ] = new DownloadQueueSet( defaultBulkDownloadPolicy );
}

HttpDownloadManager::Private::~Private()
{
    QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = m_defaultQueueSets.begin();
    QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = m_defaultQueueSets.end();
    for (; pos != end; ++pos )
        delete pos.value();
}

DownloadQueueSet *HttpDownloadManager::Private::findQueues( const QString& hostName,
                                                            const DownloadUsage usage )
{
    DownloadQueueSet * result = 0;
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator pos = m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator const end = m_queueSets.end();
    for (; pos != end; ++pos ) {
        if ( (*pos).first.matches( hostName, usage )) {
            result = (*pos).second;
            break;
        }
    }
    if ( !result ) {
        mDebug() << "No download policy found for" << hostName << usage
                 << ", using default policy.";
        result = m_defaultQueueSets[ usage ];
    }
    return result;
}

HttpDownloadManager::HttpDownloadManager( StoragePolicy *policy )
    : d( new Private( policy ) )
{
    d->m_requeueTimer.setInterval( requeueTime );
    connect( &d->m_requeueTimer, SIGNAL(timeout()), this, SLOT(requeue()) );
    connectDefaultQueueSets();
}

HttpDownloadManager::~HttpDownloadManager()
{
    delete d;
}

void HttpDownloadManager::setDownloadEnabled( const bool enable )
{
    d->m_networkAccessManager.setNetworkAccessible( enable ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible );
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        pos->second->purgeJobs();
    }

}

void HttpDownloadManager::addDownloadPolicy( const DownloadPolicy& policy )
{
    if ( hasDownloadPolicy( policy ))
        return;
    DownloadQueueSet * const queueSet = new DownloadQueueSet( policy, this );
    connectQueueSet( queueSet );
    d->m_queueSets.append( QPair<DownloadPolicyKey, DownloadQueueSet *>
                           ( queueSet->downloadPolicy().key(), queueSet ));
}

void HttpDownloadManager::addJob( const QUrl& sourceUrl, const QString& destFileName,
                                  const QString &id, const DownloadUsage usage )
{
    if ( d->m_networkAccessManager.networkAccessible() == QNetworkAccessManager::NotAccessible )
        return;

    DownloadQueueSet * const queueSet = d->findQueues( sourceUrl.host(), usage );
    if ( queueSet->canAcceptJob( sourceUrl, destFileName )) {
        HttpJob * const job = new HttpJob( sourceUrl, destFileName, id, &d->m_networkAccessManager );
        job->setUserAgentPluginId( "QNamNetworkPlugin" );
        job->setDownloadUsage( usage );
        queueSet->addJob( job );
    }
}

void HttpDownloadManager::finishJob( const QByteArray& data, const QString& destinationFileName,
                                     const QString& id )
{
    mDebug() << "emitting downloadComplete( QByteArray, " << id << ")";
    emit downloadComplete( data, id );
    if ( d->m_storagePolicy ) {
        const bool saved = d->m_storagePolicy->updateFile( destinationFileName, data );
        if ( saved ) {
            mDebug() << "emitting downloadComplete( " << destinationFileName << ", " << id << ")";
            emit downloadComplete( destinationFileName, id );
        } else {
            qWarning() << "Could not save:" << destinationFileName;
        }
    }
}

void HttpDownloadManager::requeue()
{
    d->m_requeueTimer.stop();

    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        (*pos).second->retryJobs();
    }
}

void HttpDownloadManager::startRetryTimer()
{
    if ( !d->m_requeueTimer.isActive() )
        d->m_requeueTimer.start();
}

void HttpDownloadManager::connectDefaultQueueSets()
{
    QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = d->m_defaultQueueSets.begin();
    QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = d->m_defaultQueueSets.end();
    for (; pos != end; ++pos )
        connectQueueSet( pos.value() );
}

void HttpDownloadManager::connectQueueSet( DownloadQueueSet * queueSet )
{
    connect( queueSet, SIGNAL(jobFinished(QByteArray,QString,QString)),
             SLOT(finishJob(QByteArray,QString,QString)));
    connect( queueSet, SIGNAL(jobRetry()), SLOT(startRetryTimer()));
    connect( queueSet, SIGNAL(jobRedirected(QUrl,QString,QString,DownloadUsage)),
             SLOT(addJob(QUrl,QString,QString,DownloadUsage)));
    // relay jobAdded/jobRemoved signals (interesting for progress bar)
    connect( queueSet, SIGNAL(jobAdded()), SIGNAL(jobAdded()));
    connect( queueSet, SIGNAL(jobRemoved()), SIGNAL(jobRemoved()));
    connect( queueSet, SIGNAL(progressChanged(int,int)), SIGNAL(progressChanged(int,int)) );
}

bool HttpDownloadManager::hasDownloadPolicy( const DownloadPolicy& policy ) const
{
    bool found = false;
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator pos = d->m_queueSets.begin();
    QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator const end = d->m_queueSets.end();
    for (; pos != end; ++pos ) {
        if ( (*pos).second->downloadPolicy() == policy ) {
            found = true;
            break;
        }
    }
    return found;
}

#include "HttpDownloadManager.moc"
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "util/sexpr/option_declarations.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/tactic/expr_to_tactic.h"
#include "library/simplifier/simp_tactic.h"

#ifndef LEAN_DEFAULT_SIMP_SINGLE_PASS
#define LEAN_DEFAULT_SIMP_SINGLE_PASS false
#endif

#ifndef LEAN_DEFAULT_SIMP_BOTTOM_UP
#define LEAN_DEFAULT_SIMP_BOTTOM_UP true
#endif

#ifndef LEAN_DEFAULT_SIMP_BETA_ETA
#define LEAN_DEFAULT_SIMP_BETA_ETA true
#endif

#ifndef LEAN_DEFAULT_SIMP_IOTA
#define LEAN_DEFAULT_SIMP_IOTA true
#endif

#ifndef LEAN_DEFAULT_SIMP_MEMOIZE
#define LEAN_DEFAULT_SIMP_MEMOIZE true
#endif

#ifndef LEAN_DEFAULT_SIMP_MAX_STEPS
#define LEAN_DEFAULT_SIMP_MAX_STEPS 10000
#endif

#ifndef LEAN_DEFAULT_SIMP_TRACE
#define LEAN_DEFAULT_SIMP_TRACE false
#endif

#ifndef LEAN_DEFAULT_SIMP_ASSUMPTIONS
#define LEAN_DEFAULT_SIMP_ASSUMPTIONS false
#endif

#ifndef LEAN_DEFAULT_SIMP_FUNEXT
#define LEAN_DEFAULT_SIMP_FUNEXT true
#endif

#ifndef LEAN_DEFAULT_SIMP_PROPEXT
#define LEAN_DEFAULT_SIMP_PROPEXT true
#endif

namespace lean {
name const * g_simp_single_pass = nullptr;
name const * g_simp_bottom_up   = nullptr;
name const * g_simp_beta_eta    = nullptr;
name const * g_simp_iota        = nullptr;
name const * g_simp_memoize     = nullptr;
name const * g_simp_max_steps   = nullptr;
name const * g_simp_trace       = nullptr;
name const * g_simp_assumptions = nullptr;
name const * g_simp_funext      = nullptr;
name const * g_simp_propext     = nullptr;

bool get_simp_single_pass(options const & opts) {
    return opts.get_bool(*g_simp_single_pass, LEAN_DEFAULT_SIMP_SINGLE_PASS);
}

bool get_simp_bottom_up(options const & opts) {
    return opts.get_bool(*g_simp_bottom_up, LEAN_DEFAULT_SIMP_BOTTOM_UP);
}

bool get_simp_beta_eta(options const & opts) {
    return opts.get_bool(*g_simp_beta_eta, LEAN_DEFAULT_SIMP_BETA_ETA);
}

bool get_simp_iota(options const & opts) {
    return opts.get_bool(*g_simp_iota, LEAN_DEFAULT_SIMP_IOTA);
}

bool get_simp_memoize(options const & opts) {
    return opts.get_bool(*g_simp_memoize, LEAN_DEFAULT_SIMP_MEMOIZE);
}

unsigned get_simp_max_steps(options const & opts) {
    return opts.get_bool(*g_simp_max_steps, LEAN_DEFAULT_SIMP_MAX_STEPS);
}

bool get_simp_trace(options const & opts) {
    return opts.get_bool(*g_simp_trace, LEAN_DEFAULT_SIMP_TRACE);
}

bool get_simp_assumptions(options const & opts) {
    return opts.get_bool(*g_simp_assumptions, LEAN_DEFAULT_SIMP_ASSUMPTIONS);
}

bool get_simp_funext(options const & opts) {
    return opts.get_bool(*g_simp_funext, LEAN_DEFAULT_SIMP_FUNEXT);
}

bool get_simp_propext(options const & opts) {
    return opts.get_bool(*g_simp_propext, LEAN_DEFAULT_SIMP_PROPEXT);
}

expr const * g_simp_tactic = nullptr;

expr mk_simp_tactic_expr(buffer<expr> const & ls, buffer<name> const & ns,
                         buffer<name> const & ex, optional<expr> const & pre_tac,
                         location const & loc) {
    expr e  = mk_expr_list(ls.size(), ls.data());
    expr n  = ids_to_tactic_expr(ns);
    expr x  = ids_to_tactic_expr(ex);
    expr t;
    if (pre_tac) {
        t = mk_app(mk_constant(get_option_some_name()), *pre_tac);
    } else {

        t = mk_constant(get_option_none_name());
    }
    expr l = mk_location_expr(loc);
    expr r = mk_app({*g_simp_tactic, e, n, x, t, l});
    return r;
}

class simp_tactic_fn {
    environment      m_env;
    io_state         m_ios;
    name_generator   m_ngen;
    optional<tactic> m_tactic;

    // transient state
    unsigned         m_steps;
    goal             m_g;

    // configuration options
    bool     m_single_pass;
    bool     m_bottom_up;
    bool     m_beta_eta;
    bool     m_iota;
    bool     m_memoize;
    unsigned m_max_steps;
    bool     m_trace;
    bool     m_assumptions;
    bool     m_funext;
    bool     m_propext;
    bool     m_standard;

    void set_options(environment const & env, options const & o) {
        m_single_pass = get_simp_single_pass(o);
        m_bottom_up   = get_simp_bottom_up(o);
        m_beta_eta    = get_simp_beta_eta(o);
        m_iota        = get_simp_iota(o);
        m_memoize     = get_simp_memoize(o);
        m_max_steps   = get_simp_max_steps(o);
        m_trace       = get_simp_trace(o);
        m_assumptions = get_simp_assumptions(o);
        if (is_standard(env)) {
            m_funext   = get_simp_funext(o) && env.find(get_funext_name());
            m_propext  = get_simp_propext(o) && env.find(get_propext_name());
            m_standard = true;
        } else {
            // TODO(Leo): add support for function extensionality in HoTT mode
            m_funext      = false;
            m_propext     = false;
            m_standard    = false;
        }
    }

public:
    simp_tactic_fn(environment const & env, io_state const & ios, name_generator && ngen,
                   buffer<expr> const & /* ls */, buffer<name> const & /* ns */, buffer<name> const & /* ex */,
                   optional<tactic> const & tac):m_env(env), m_ios(ios), m_ngen(ngen), m_tactic(tac) {
        set_options(env, m_ios.get_options());
    }

    enum res_kind { Simplified, Solved, DidNothing };

    std::tuple<res_kind, goal, substitution> operator()(goal const & g, location const & /* loc */, substitution const & s) {
        m_g     = g;
        m_steps = 0;

        // TODO(Leo)
        return std::make_tuple(DidNothing, g, s);
    }
};

tactic mk_simp_tactic(elaborate_fn const & elab, buffer<expr> const & ls, buffer<name> const & ns,
                      buffer<name> const & ex, optional<tactic> tac, location const & loc) {
    return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
            goals const & gs = s.get_goals();
            if (empty(gs)) {
                throw_no_goal_if_enabled(s);
                return none_proof_state();
            }
            goal const & g = head(gs);
            name_generator new_ngen  = s.get_ngen();
            substitution   new_subst = s.get_subst();
            buffer<expr>   new_ls;
            for (expr const & l : ls) {
                expr new_l; constraints cs;
                bool report_unassigned = true;
                std::tie(new_l, new_subst, cs) = elab(g, new_ngen.mk_child(), l, none_expr(), new_subst, report_unassigned);
                if (cs)
                    throw_tactic_exception_if_enabled(s, "invalid 'simp' tactic, fail to resolve generated constraints");
                new_ls.push_back(new_l);
            }
            simp_tactic_fn simp(env, ios, new_ngen.mk_child(), new_ls, ns, ex, tac);
            goal new_g; simp_tactic_fn::res_kind k;
            std::tie(k, new_g, new_subst) = simp(g, loc, new_subst);
            switch (k) {
            case simp_tactic_fn::Simplified: {
                proof_state new_s(s, cons(new_g, tail(gs)), new_subst, new_ngen);
                return some_proof_state(new_s);
            }
            case simp_tactic_fn::Solved: {
                proof_state new_s(s, tail(gs), new_subst, new_ngen);
                return some_proof_state(new_s);
            }
            case simp_tactic_fn::DidNothing:
                return none_proof_state();
            }
            lean_unreachable();
        });
}

void initialize_simp_tactic() {
    name simp_name{"tactic", "simp_tac"};
    g_simp_tactic = new expr(mk_constant(simp_name));

    register_tac(simp_name,
                 [](type_checker & tc, elaborate_fn const & elab, expr const & e, pos_info_provider const * p) {
                     buffer<expr> args;
                     get_app_args(e, args);
                     if (args.size() != 5)
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, incorrect number of arguments");
                     buffer<expr> lemmas;
                     get_tactic_expr_list_elements(args[0], lemmas, "invalid 'simp' tactic, invalid argument #1");
                     buffer<name> ns, ex;
                     get_tactic_id_list_elements(args[1], ns, "invalid 'simp' tactic, invalid argument #2");
                     get_tactic_id_list_elements(args[2], ex, "invalid 'simp' tactic, invalid argument #3");
                     optional<tactic> tac;
                     expr A, t;
                     if (is_some(args[3], A, t)) {
                         tac = expr_to_tactic(tc, elab, t, p);
                     } else if (is_none(args[3], A)) {
                         // do nothing
                     } else {
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, invalid argument #4");
                     }
                     check_tactic_expr(args[4], "invalid 'simp' tactic, invalid argument #5");
                     expr loc_expr = get_tactic_expr_expr(args[4]);
                     if (!is_location_expr(loc_expr))
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, invalid argument #5");
                     location loc = get_location_expr_location(loc_expr);
                     return mk_simp_tactic(elab, lemmas, ns, ex, tac, loc);
                 });

    g_simp_single_pass = new name{"simp", "single_pass"};
    register_bool_option(*g_simp_single_pass, LEAN_DEFAULT_SIMP_SINGLE_PASS,
                         "(simp tactic) if false then the simplifier keeps applying simplifications as long as possible");

    g_simp_bottom_up = new name{"simp", "bottom_up"};
    register_bool_option(*g_simp_bottom_up, LEAN_DEFAULT_SIMP_BOTTOM_UP,
                         "(simp tactic) if true the simplifier uses a bottom up rewriting strategy, otherwise it uses top down");

    g_simp_beta_eta = new name{"simp", "beta_eta"};
    register_bool_option(*g_simp_beta_eta, LEAN_DEFAULT_SIMP_BETA_ETA,
                         "(simp tactic) if true the simplifier applies beta and eta reduction");

    g_simp_iota = new name{"simp", "iota"};
    register_bool_option(*g_simp_iota, LEAN_DEFAULT_SIMP_IOTA,
                         "(simp tactic) if true the simplifier applies iota reduction");

    g_simp_memoize = new name{"simp", "memoize"};
    register_bool_option(*g_simp_memoize, LEAN_DEFAULT_SIMP_MEMOIZE,
                         "(simp tactic) if true the simplifier caches intermediate results");

    g_simp_max_steps = new name{"simp", "max_steps"};
    register_unsigned_option(*g_simp_max_steps, LEAN_DEFAULT_SIMP_MAX_STEPS,
                             "(simp tactic) maximum number of steps that can be performed by the simplifier");

    g_simp_trace = new name{"simp", "trace"};
    register_bool_option(*g_simp_trace, LEAN_DEFAULT_SIMP_TRACE,
                         "(simp tactic) if true the simplifier produces an execution trace for debugging purposes");

    g_simp_assumptions = new name{"simp", "assumptions"};
    register_bool_option(*g_simp_assumptions, LEAN_DEFAULT_SIMP_ASSUMPTIONS,
                         "(simp tactic) if true assumptions/hypotheses are automatically used as rewriting rules");

    g_simp_funext = new name{"simp", "funext"};
    register_bool_option(*g_simp_funext, LEAN_DEFAULT_SIMP_FUNEXT,
                         "(simp tactic) avoid function extensionality even if theorem/axiom is in the environment");

    g_simp_propext = new name{"simp", "propext"};
    register_bool_option(*g_simp_funext, LEAN_DEFAULT_SIMP_PROPEXT,
                         "(simp tactic) avoid proposition extensionality even if axiom is in the environment, this option is ignored in HoTT mode");
}

void finalize_simp_tactic() {
    delete g_simp_tactic;
    delete g_simp_single_pass;
    delete g_simp_bottom_up;
    delete g_simp_beta_eta;
    delete g_simp_iota;
    delete g_simp_memoize;
    delete g_simp_max_steps;
    delete g_simp_trace;
    delete g_simp_assumptions;
    delete g_simp_funext;
    delete g_simp_propext;
}
}
<commit_msg>refactor(library/simplifier): cleanup<commit_after>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "util/sexpr/option_declarations.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/tactic/expr_to_tactic.h"
#include "library/simplifier/simp_tactic.h"

#ifndef LEAN_DEFAULT_SIMP_SINGLE_PASS
#define LEAN_DEFAULT_SIMP_SINGLE_PASS false
#endif

#ifndef LEAN_DEFAULT_SIMP_BOTTOM_UP
#define LEAN_DEFAULT_SIMP_BOTTOM_UP true
#endif

#ifndef LEAN_DEFAULT_SIMP_BETA_ETA
#define LEAN_DEFAULT_SIMP_BETA_ETA true
#endif

#ifndef LEAN_DEFAULT_SIMP_IOTA
#define LEAN_DEFAULT_SIMP_IOTA true
#endif

#ifndef LEAN_DEFAULT_SIMP_MEMOIZE
#define LEAN_DEFAULT_SIMP_MEMOIZE true
#endif

#ifndef LEAN_DEFAULT_SIMP_MAX_STEPS
#define LEAN_DEFAULT_SIMP_MAX_STEPS 10000
#endif

#ifndef LEAN_DEFAULT_SIMP_TRACE
#define LEAN_DEFAULT_SIMP_TRACE false
#endif

#ifndef LEAN_DEFAULT_SIMP_ASSUMPTIONS
#define LEAN_DEFAULT_SIMP_ASSUMPTIONS false
#endif

#ifndef LEAN_DEFAULT_SIMP_FUNEXT
#define LEAN_DEFAULT_SIMP_FUNEXT true
#endif

#ifndef LEAN_DEFAULT_SIMP_PROPEXT
#define LEAN_DEFAULT_SIMP_PROPEXT true
#endif

namespace lean {
name const * g_simp_single_pass = nullptr;
name const * g_simp_bottom_up   = nullptr;
name const * g_simp_beta_eta    = nullptr;
name const * g_simp_iota        = nullptr;
name const * g_simp_memoize     = nullptr;
name const * g_simp_max_steps   = nullptr;
name const * g_simp_trace       = nullptr;
name const * g_simp_assumptions = nullptr;
name const * g_simp_funext      = nullptr;
name const * g_simp_propext     = nullptr;

bool get_simp_single_pass(options const & opts) {
    return opts.get_bool(*g_simp_single_pass, LEAN_DEFAULT_SIMP_SINGLE_PASS);
}

bool get_simp_bottom_up(options const & opts) {
    return opts.get_bool(*g_simp_bottom_up, LEAN_DEFAULT_SIMP_BOTTOM_UP);
}

bool get_simp_beta_eta(options const & opts) {
    return opts.get_bool(*g_simp_beta_eta, LEAN_DEFAULT_SIMP_BETA_ETA);
}

bool get_simp_iota(options const & opts) {
    return opts.get_bool(*g_simp_iota, LEAN_DEFAULT_SIMP_IOTA);
}

bool get_simp_memoize(options const & opts) {
    return opts.get_bool(*g_simp_memoize, LEAN_DEFAULT_SIMP_MEMOIZE);
}

unsigned get_simp_max_steps(options const & opts) {
    return opts.get_bool(*g_simp_max_steps, LEAN_DEFAULT_SIMP_MAX_STEPS);
}

bool get_simp_trace(options const & opts) {
    return opts.get_bool(*g_simp_trace, LEAN_DEFAULT_SIMP_TRACE);
}

bool get_simp_assumptions(options const & opts) {
    return opts.get_bool(*g_simp_assumptions, LEAN_DEFAULT_SIMP_ASSUMPTIONS);
}

bool get_simp_funext(options const & opts) {
    return opts.get_bool(*g_simp_funext, LEAN_DEFAULT_SIMP_FUNEXT);
}

bool get_simp_propext(options const & opts) {
    return opts.get_bool(*g_simp_propext, LEAN_DEFAULT_SIMP_PROPEXT);
}

expr const * g_simp_tactic = nullptr;

expr mk_simp_tactic_expr(buffer<expr> const & ls, buffer<name> const & ns,
                         buffer<name> const & ex, optional<expr> const & pre_tac,
                         location const & loc) {
    expr e  = mk_expr_list(ls.size(), ls.data());
    expr n  = ids_to_tactic_expr(ns);
    expr x  = ids_to_tactic_expr(ex);
    expr t;
    if (pre_tac) {
        t = mk_app(mk_constant(get_option_some_name()), *pre_tac);
    } else {

        t = mk_constant(get_option_none_name());
    }
    expr l = mk_location_expr(loc);
    expr r = mk_app({*g_simp_tactic, e, n, x, t, l});
    return r;
}

class simp_tactic_fn {
public:
    enum res_kind { Simplified, Solved, DidNothing };
private:
    environment      m_env;
    io_state         m_ios;
    name_generator   m_ngen;
    optional<tactic> m_tactic;

    // transient state
    unsigned         m_steps;
    goal             m_g;
    substitution     m_subst;

    // configuration options
    bool     m_single_pass;
    bool     m_bottom_up;
    bool     m_beta_eta;
    bool     m_iota;
    bool     m_memoize;
    unsigned m_max_steps;
    bool     m_trace;
    bool     m_assumptions;
    bool     m_funext;
    bool     m_propext;
    bool     m_standard;

    void set_options(environment const & env, options const & o) {
        m_single_pass = get_simp_single_pass(o);
        m_bottom_up   = get_simp_bottom_up(o);
        m_beta_eta    = get_simp_beta_eta(o);
        m_iota        = get_simp_iota(o);
        m_memoize     = get_simp_memoize(o);
        m_max_steps   = get_simp_max_steps(o);
        m_trace       = get_simp_trace(o);
        m_assumptions = get_simp_assumptions(o);
        if (is_standard(env)) {
            m_funext   = get_simp_funext(o) && env.find(get_funext_name());
            m_propext  = get_simp_propext(o) && env.find(get_propext_name());
            m_standard = true;
        } else {
            // TODO(Leo): add support for function extensionality in HoTT mode
            m_funext      = false;
            m_propext     = false;
            m_standard    = false;
        }
    }

    res_kind simp_goal() {
        // TODO(Leo)
        return DidNothing;
    }

    bool simp_hyp(unsigned hidx) {
        // TODO(Leo)
        return false;
    }

public:
    simp_tactic_fn(environment const & env, io_state const & ios, name_generator && ngen,
                   buffer<expr> const & /* ls */, buffer<name> const & /* ns */, buffer<name> const & /* ex */,
                   optional<tactic> const & tac):m_env(env), m_ios(ios), m_ngen(ngen), m_tactic(tac) {
        set_options(env, m_ios.get_options());
    }

    std::tuple<res_kind, goal, substitution> operator()(goal const & g, location const & loc, substitution const & s) {
        m_g     = g;
        m_subst = s;
        if (loc.is_goal_only()) {
            res_kind k = simp_goal();
            return std::make_tuple(k, m_g, m_subst);
        } else {
            buffer<expr> hyps;
            m_g.get_hyps(hyps);
            bool progress = false;
            unsigned hidx = 0;
            for (expr const & h : hyps) {
                if (loc.includes_hypothesis(local_pp_name(h))) {
                    if (simp_hyp(hidx))
                        progress = true;
                }
                hidx++;
            }
            if (loc.includes_goal()) {
                res_kind k = simp_goal();
                if (k == DidNothing && progress)
                    k = Simplified;
                return std::make_tuple(k, m_g, m_subst);
            } else {
                return std::make_tuple(progress ? Simplified : DidNothing, m_g, m_subst);
            }
        }
    }
};

tactic mk_simp_tactic(elaborate_fn const & elab, buffer<expr> const & ls, buffer<name> const & ns,
                      buffer<name> const & ex, optional<tactic> tac, location const & loc) {
    return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
            goals const & gs = s.get_goals();
            if (empty(gs)) {
                throw_no_goal_if_enabled(s);
                return none_proof_state();
            }
            goal const & g = head(gs);
            name_generator new_ngen  = s.get_ngen();
            substitution   new_subst = s.get_subst();
            buffer<expr>   new_ls;
            for (expr const & l : ls) {
                expr new_l; constraints cs;
                bool report_unassigned = true;
                std::tie(new_l, new_subst, cs) = elab(g, new_ngen.mk_child(), l, none_expr(), new_subst, report_unassigned);
                if (cs)
                    throw_tactic_exception_if_enabled(s, "invalid 'simp' tactic, fail to resolve generated constraints");
                new_ls.push_back(new_l);
            }
            simp_tactic_fn simp(env, ios, new_ngen.mk_child(), new_ls, ns, ex, tac);
            goal new_g; simp_tactic_fn::res_kind k;
            std::tie(k, new_g, new_subst) = simp(g, loc, new_subst);
            switch (k) {
            case simp_tactic_fn::Simplified: {
                proof_state new_s(s, cons(new_g, tail(gs)), new_subst, new_ngen);
                return some_proof_state(new_s);
            }
            case simp_tactic_fn::Solved: {
                proof_state new_s(s, tail(gs), new_subst, new_ngen);
                return some_proof_state(new_s);
            }
            case simp_tactic_fn::DidNothing:
                return none_proof_state();
            }
            lean_unreachable();
        });
}

void initialize_simp_tactic() {
    name simp_name{"tactic", "simp_tac"};
    g_simp_tactic = new expr(mk_constant(simp_name));

    register_tac(simp_name,
                 [](type_checker & tc, elaborate_fn const & elab, expr const & e, pos_info_provider const * p) {
                     buffer<expr> args;
                     get_app_args(e, args);
                     if (args.size() != 5)
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, incorrect number of arguments");
                     buffer<expr> lemmas;
                     get_tactic_expr_list_elements(args[0], lemmas, "invalid 'simp' tactic, invalid argument #1");
                     buffer<name> ns, ex;
                     get_tactic_id_list_elements(args[1], ns, "invalid 'simp' tactic, invalid argument #2");
                     get_tactic_id_list_elements(args[2], ex, "invalid 'simp' tactic, invalid argument #3");
                     optional<tactic> tac;
                     expr A, t;
                     if (is_some(args[3], A, t)) {
                         tac = expr_to_tactic(tc, elab, t, p);
                     } else if (is_none(args[3], A)) {
                         // do nothing
                     } else {
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, invalid argument #4");
                     }
                     check_tactic_expr(args[4], "invalid 'simp' tactic, invalid argument #5");
                     expr loc_expr = get_tactic_expr_expr(args[4]);
                     if (!is_location_expr(loc_expr))
                         throw expr_to_tactic_exception(e, "invalid 'simp' tactic, invalid argument #5");
                     location loc = get_location_expr_location(loc_expr);
                     return mk_simp_tactic(elab, lemmas, ns, ex, tac, loc);
                 });

    g_simp_single_pass = new name{"simp", "single_pass"};
    register_bool_option(*g_simp_single_pass, LEAN_DEFAULT_SIMP_SINGLE_PASS,
                         "(simp tactic) if false then the simplifier keeps applying simplifications as long as possible");

    g_simp_bottom_up = new name{"simp", "bottom_up"};
    register_bool_option(*g_simp_bottom_up, LEAN_DEFAULT_SIMP_BOTTOM_UP,
                         "(simp tactic) if true the simplifier uses a bottom up rewriting strategy, otherwise it uses top down");

    g_simp_beta_eta = new name{"simp", "beta_eta"};
    register_bool_option(*g_simp_beta_eta, LEAN_DEFAULT_SIMP_BETA_ETA,
                         "(simp tactic) if true the simplifier applies beta and eta reduction");

    g_simp_iota = new name{"simp", "iota"};
    register_bool_option(*g_simp_iota, LEAN_DEFAULT_SIMP_IOTA,
                         "(simp tactic) if true the simplifier applies iota reduction");

    g_simp_memoize = new name{"simp", "memoize"};
    register_bool_option(*g_simp_memoize, LEAN_DEFAULT_SIMP_MEMOIZE,
                         "(simp tactic) if true the simplifier caches intermediate results");

    g_simp_max_steps = new name{"simp", "max_steps"};
    register_unsigned_option(*g_simp_max_steps, LEAN_DEFAULT_SIMP_MAX_STEPS,
                             "(simp tactic) maximum number of steps that can be performed by the simplifier");

    g_simp_trace = new name{"simp", "trace"};
    register_bool_option(*g_simp_trace, LEAN_DEFAULT_SIMP_TRACE,
                         "(simp tactic) if true the simplifier produces an execution trace for debugging purposes");

    g_simp_assumptions = new name{"simp", "assumptions"};
    register_bool_option(*g_simp_assumptions, LEAN_DEFAULT_SIMP_ASSUMPTIONS,
                         "(simp tactic) if true assumptions/hypotheses are automatically used as rewriting rules");

    g_simp_funext = new name{"simp", "funext"};
    register_bool_option(*g_simp_funext, LEAN_DEFAULT_SIMP_FUNEXT,
                         "(simp tactic) avoid function extensionality even if theorem/axiom is in the environment");

    g_simp_propext = new name{"simp", "propext"};
    register_bool_option(*g_simp_funext, LEAN_DEFAULT_SIMP_PROPEXT,
                         "(simp tactic) avoid proposition extensionality even if axiom is in the environment, this option is ignored in HoTT mode");
}

void finalize_simp_tactic() {
    delete g_simp_tactic;
    delete g_simp_single_pass;
    delete g_simp_bottom_up;
    delete g_simp_beta_eta;
    delete g_simp_iota;
    delete g_simp_memoize;
    delete g_simp_max_steps;
    delete g_simp_trace;
    delete g_simp_assumptions;
    delete g_simp_funext;
    delete g_simp_propext;
}
}
<|endoftext|>