<commit_before>/**
 *  Copyright 2014-2016 CyberVision, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <memory>
#include <condition_variable>

#include <kaa/Kaa.hpp>
#include <kaa/logging/Log.hpp>
#include <kaa/logging/LoggingUtils.hpp>
#include <kaa/notification/INotificationTopicListListener.hpp>
#include <kaa/common/exception/UnavailableTopicException.hpp>

using namespace kaa;

static void showTopicList(const Topics &topics)
{
    if (topics.empty()) {
        std::cout << "Topic list is empty" << std::endl;
    } else {
        for (const auto& topic : topics) {
            std::cout << (boost::format("Topic: id '%1%', name '%2%', type '%3%'")
                % topic.id % topic.name % LoggingUtils::toString(topic.subscriptionType)) << std::endl;
        }
    }
}

static std::list<int64_t> extractOptionalTopicIds(const Topics& topics)
{
    std::list<int64_t> topicIds;
    for (const auto& topic : topics) {
        if (topic.subscriptionType == SubscriptionType::OPTIONAL_SUBSCRIPTION) {
            topicIds.push_back(topic.id);
        }
    }
    return topicIds;
}

static std::string alertTypeToString(const kaa_notification::AlertType alertType)
{
    switch(alertType) {
        case kaa_notification::CodeRed:
            return "CodeRed";
        case kaa_notification::CodeYellow:
            return "CodeYellow";
        case kaa_notification::CodeGreen:
            return "CodeGreen";
        default:
            return "Unknown type";
    }
}

class NotificationListener : public INotificationListener {
public:
    NotificationListener(std::shared_ptr<IKaaClient> kaaClient, bool &quitFlag,
            std::condition_variable &doQuit, std::mutex &quitMutex):
        kaaClient_(kaaClient), quitFlag_(quitFlag), doQuit_(doQuit), quitMutex_(quitMutex)
    {}

    void onNotification(const int64_t topicId, const KaaNotification &notification) override
    {
        auto topics = kaaClient_->getTopics();
        const auto &topic = std::find_if(topics.begin(), topics.end(),
                [topicId](const Topic &t) { return t.id == topicId; });
        std::cout << (boost::format("Notification for topic id '%1%' and name '%2%' received") % topicId % topic->name) << std::endl;
        std::cout << (boost::format("Alert type %1%, Alert message %2%") %
                alertTypeToString(notification.alertType) %
                (notification.alertMessage.empty() ? "Body is empty" : notification.alertMessage)) << std::endl;
        if (topic->subscriptionType == SubscriptionType::OPTIONAL_SUBSCRIPTION) {
            std::unique_lock<std::mutex> lock(quitMutex_);
            quitFlag_ = true;
            doQuit_.notify_one();
        }
    }

private:
    std::shared_ptr<IKaaClient> kaaClient_;
    bool &quitFlag_;
    std::condition_variable &doQuit_;
    std::mutex &quitMutex_;
};

class TopicListListener : public INotificationTopicListListener {
public:

    TopicListListener(std::shared_ptr<IKaaClient> kaaClient, bool &quitFlag,
            std::condition_variable &doQuit, std::mutex &quitMutex):
        kaaClient_(kaaClient), quitFlag_(quitFlag), doQuit_(doQuit), quitMutex_(quitMutex)
    {}

    void onListUpdated(const Topics& topics) override
    {
        std::cout << "Topic list was updated" << std::endl;
        showTopicList(topics);
        optionalTopicsList_ = extractOptionalTopicIds(topics);
        while (true) {
            std::cout << "Enter topic id to subscribe to" << std::endl;
            std::cout << "Enter 'quit' to exit" << std::endl;
            std::cin.clear();

            int64_t topicId;
            std::string input;
            std::cin >> input;

            if (input == "quit") {
                std::unique_lock<std::mutex> lock(quitMutex_);
                quitFlag_ = true;
                doQuit_.notify_one();
                return;
            }

            try {
                topicId = std::stoll(input);
            } catch (std::exception& e) {
                std::cout << (boost::format("Incorrect topicId: '%1%'") % input) << std::endl;
                continue;
            }

            try {
                kaaClient_->subscribeToTopic(topicId);
                kaaClient_->syncTopicSubscriptions();
                std::cout << (boost::format("Subscribed to topic '%1%'") % topicId) << std::endl;
                return;
            } catch (KaaException &e) {
                std::cout << (boost::format("Topic '%1%' is unavailable, can't subscribe") % topicId) << std::endl;
                continue;
            }
        }
    }

    std::list<int64_t> getOptionalTopicList() const
    {
        return optionalTopicsList_;
    }

private:
    std::list<int64_t> optionalTopicsList_;
    std::shared_ptr<IKaaClient> kaaClient_;
    bool &quitFlag_;
    std::condition_variable &doQuit_;
    std::mutex &quitMutex_;
};

int main()
{
    auto kaaClient = Kaa::newClient();

    bool quitFlag = false;
    std::condition_variable doQuit;
    std::mutex quitMutex;

    TopicListListener topicListListener(kaaClient, quitFlag, doQuit, quitMutex);
    kaaClient->addTopicListListener(topicListListener);

    NotificationListener notificationListener(kaaClient, quitFlag, doQuit, quitMutex);
    kaaClient->addNotificationListener(notificationListener);

    kaaClient->start();

    std::cout << "Notification demo started" << std::endl;

    {
        std::unique_lock<std::mutex> lock(quitMutex);
        doQuit.wait(lock, [&quitFlag] { return quitFlag; });
    }

    kaaClient->stop();

    return 0;
}

<commit_msg>APP-475: Fix notification demo flow<commit_after>/**
 *  Copyright 2014-2016 CyberVision, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <memory>
#include <condition_variable>

#include <kaa/Kaa.hpp>
#include <kaa/logging/Log.hpp>
#include <kaa/logging/LoggingUtils.hpp>
#include <kaa/notification/INotificationTopicListListener.hpp>
#include <kaa/common/exception/UnavailableTopicException.hpp>

using namespace kaa;

static constexpr auto TOPIC_LIST_UPDATE_TIMEOUT = 3;

static void showTopicList(const Topics &topics)
{
    if (topics.empty()) {
        std::cout << "Topic list is empty" << std::endl;
    } else {
        for (const auto& topic : topics) {
            std::cout << (boost::format("Topic: id '%1%', name '%2%', type '%3%'")
                % topic.id % topic.name % LoggingUtils::toString(topic.subscriptionType)) << std::endl;
        }
    }
}

static std::list<int64_t> extractOptionalTopicIds(const Topics& topics)
{
    std::list<int64_t> topicIds;
    for (const auto& topic : topics) {
        if (topic.subscriptionType == SubscriptionType::OPTIONAL_SUBSCRIPTION) {
            topicIds.push_back(topic.id);
        }
    }
    return topicIds;
}

static std::string alertTypeToString(const kaa_notification::AlertType alertType)
{
    switch(alertType) {
        case kaa_notification::CodeRed:
            return "CodeRed";
        case kaa_notification::CodeYellow:
            return "CodeYellow";
        case kaa_notification::CodeGreen:
            return "CodeGreen";
        default:
            return "Unknown type";
    }
}

class NotificationListener : public INotificationListener {
public:
    NotificationListener(std::shared_ptr<IKaaClient> kaaClient):
        kaaClient_(kaaClient)
    {}

    void onNotification(const int64_t topicId, const KaaNotification &notification) override
    {
        auto topics = kaaClient_->getTopics();
        const auto &topic = std::find_if(topics.begin(), topics.end(),
                [topicId](const Topic &t) { return t.id == topicId; });
        std::cout << (boost::format("Notification for topic id '%1%' and name '%2%' received") % topicId % topic->name) << std::endl;
        std::cout << (boost::format("Alert type %1%, Alert message %2%") %
                alertTypeToString(notification.alertType) %
                (notification.alertMessage.empty() ? "Body is empty" : notification.alertMessage)) << std::endl;
    }

private:
    std::shared_ptr<IKaaClient> kaaClient_;
};

class TopicListListener : public INotificationTopicListListener {
public:

    TopicListListener(std::shared_ptr<IKaaClient> kaaClient, bool &updatedFlag,
            std::condition_variable &updatedVar, std::mutex &updatedMutex):
        kaaClient_(kaaClient), updatedFlag_(updatedFlag), updatedVar_(updatedVar), updatedMutex_(updatedMutex)
    {}

    void onListUpdated(const Topics& topics) override
    {
        std::cout << "Topic list was updated" << std::endl;
        showTopicList(topics);
        optionalTopicsList_ = extractOptionalTopicIds(topics);
        std::unique_lock<std::mutex> lock(updatedMutex_);
        updatedFlag_ = true;
        updatedVar_.notify_one();
    }

    std::list<int64_t> getOptionalTopicList() const
    {
        return optionalTopicsList_;
    }

private:
    std::list<int64_t> optionalTopicsList_;
    std::shared_ptr<IKaaClient> kaaClient_;
    bool &updatedFlag_;
    std::condition_variable &updatedVar_;
    std::mutex &updatedMutex_;
};

int main()
{
    auto kaaClient = Kaa::newClient();

    bool updatedFlag = false;
    std::condition_variable updatedVar;
    std::mutex updatedMutex;

    TopicListListener topicListListener(kaaClient, updatedFlag, updatedVar, updatedMutex);
    kaaClient->addTopicListListener(topicListListener);

    NotificationListener notificationListener(kaaClient);
    kaaClient->addNotificationListener(notificationListener);

    kaaClient->start();

    std::cout << "Notification demo started" << std::endl;

    {
        std::unique_lock<std::mutex> lock(updatedMutex);
        if (!updatedVar.wait_for(lock, std::chrono::seconds(TOPIC_LIST_UPDATE_TIMEOUT),
                    [&updatedFlag] { return updatedFlag; })) {
            std::cout << "Timed out waiting for topic list update" << std::endl;
            kaaClient->stop();
            return EXIT_SUCCESS;
        }
    }

    while (true) {
        std::cout << "Enter topic id to subscribe to" << std::endl;
        std::cout << "Enter 'quit' to exit" << std::endl;
        std::cin.clear();

        int64_t topicId;
        std::string input;
        std::cin >> input;

        if (input == "quit") {
            break;
        }

        try {
            topicId = std::stoll(input);
        } catch (const std::exception& e) {
            std::cout << (boost::format("Incorrect topicId: '%1%'") % input) << std::endl;
            continue;
        }

        try {
            kaaClient->subscribeToTopic(topicId);
            kaaClient->syncTopicSubscriptions();
            std::cout << (boost::format("Subscribed to topic '%1%'") % topicId) << std::endl;
        } catch (const KaaException &e) {
            std::cout << (boost::format("Topic '%1%' is unavailable, can't subscribe") % topicId) << std::endl;
            continue;
        }
    }

    kaaClient->stop();

    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#ifndef ASTRA_CONFIGURATION_H
#define ASTRA_CONFIGURATION_H

#include <Astra/astra_types.h>
#include <string>

namespace astra {

    class configuration
    {
    public:
        configuration();

        astra_log_severity_t severityLevel() { return severityLevel_; }
        void set_severityLevel(astra_log_severity_t level) { severityLevel_ = level; }

        const std::string& pluginsPath() const { return pluginsPath_; }
        void set_pluginsPath(std::string pluginsPath) { pluginsPath_ = pluginsPath; }

        static configuration* load_from_file(const char* tomlFilePath);

    private:
        astra_log_severity_t severityLevel_{ASTRA_SEVERITY_INFO};
        std::string pluginsPath_;
    };
}

#endif /* ASTRA_CONFIGURATION_H */
<commit_msg>Change default logging level to FATAL<commit_after>#ifndef ASTRA_CONFIGURATION_H
#define ASTRA_CONFIGURATION_H

#include <Astra/astra_types.h>
#include <string>

namespace astra {

    class configuration
    {
    public:
        configuration();

        astra_log_severity_t severityLevel() { return severityLevel_; }
        void set_severityLevel(astra_log_severity_t level) { severityLevel_ = level; }

        const std::string& pluginsPath() const { return pluginsPath_; }
        void set_pluginsPath(std::string pluginsPath) { pluginsPath_ = pluginsPath; }

        static configuration* load_from_file(const char* tomlFilePath);

    private:
        astra_log_severity_t severityLevel_{ASTRA_SEVERITY_FATAL};
        std::string pluginsPath_;
    };
}

#endif /* ASTRA_CONFIGURATION_H */
<|endoftext|>


<commit_before>
#pragma once

#include <cmath>

/**
 * Uses interpolation search to find x such that y-e < f(x) < y+e.
 * The function f must be monotonic.
 **/
template<typename Function>
double find_argument(double y, Function f, double lo, double hi, double e = 1e-9) {
  using std::abs;
  double x;
  while(true) {
    x = lo + (y - f(lo)) * (hi - lo) / (f(hi) - f(lo));

    if(abs(f(x)-y) < e) return x;

    if(abs(f(x)-f(lo)) < abs(y-f(lo))) lo = x;
    else hi = x;
  }
}
<commit_msg>out of bounds check<commit_after>
#pragma once

#include <cmath>

/**
 * Uses interpolation search to find x such that y-e < f(x) < y+e.
 * The function f must be monotonic.
 **/
template<typename Function>
double find_argument(double y, Function f, double lo, double hi, double e = 1e-9) {
  using std::abs;
  double x;
  while(true) {
    x = lo + (y - f(lo)) * (hi - lo) / (f(hi) - f(lo));

    if(x < lo) return lo;
    if(x > hi) return hi;
    if(abs(f(x)-y) < e) return x;

    if(abs(f(x)-f(lo)) < abs(y-f(lo))) lo = x;
    else hi = x;
  }
}
<|endoftext|>


<commit_before><commit_msg>Fix standard exception stack write order.<commit_after><|endoftext|>


<commit_before>// Copyright 2015 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/builder/basic/kvp.hpp>
#include <bsoncxx/stdx/make_unique.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

using bsoncxx::builder::basic::kvp;
using bsoncxx::builder::basic::make_document;

int main(int, char**) {
    // The mongocxx::instance constructor and destructor initialize and shut down the driver,
    // respectively. Therefore, a mongocxx::instance must be created before using the driver and
    // must remain alive for as long as the driver is in use.
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];
    try {
        db["restaurants"].drop();
    } catch (const std::exception&) {
        // Collection did not exist.
    }

    // Create a single field index.
    {
        // @begin: cpp-single-field-index
        db["restaurants"].create_index(make_document(kvp("cusine", 1)), {});
        // @end: cpp-single-field-index
    }

    // Create a compound index.
    {
        db["restaurants"].drop();
        // @begin: cpp-create-compound-index
        db["restaurants"].create_index(make_document(kvp("cuisine", 1), kvp("address.zipcode", -1)),
                                       {});
        // @end: cpp-create-compound-index
    }

    // Create a unique index.
    {
        db["restaurants"].drop();
        // @begin: cpp-create-unique-index
        mongocxx::options::index index_options{};
        index_options.unique(true);
        db["restaurants"].create_index(make_document(kvp("website", 1)), index_options);
        // @end: cpp-create-unique-index
    }

    // Create an index with storage engine options
    {
        db["restaurants"].drop();
        // @begin: cpp-create-wt-options-index
        mongocxx::options::index index_options{};
        std::unique_ptr<mongocxx::options::index::wiredtiger_storage_options> wt_options =
            bsoncxx::stdx::make_unique<mongocxx::options::index::wiredtiger_storage_options>();
        wt_options->config_string("block_allocation=first");
        index_options.storage_options(std::move(wt_options));
        db["restaurants"].create_index(make_document(kvp("cuisine", 1)), index_options);
        // @begin: cpp-create-wt-options-index
    }
}
<commit_msg>Typo in create_index example<commit_after>// Copyright 2015 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/builder/basic/kvp.hpp>
#include <bsoncxx/stdx/make_unique.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>

using bsoncxx::builder::basic::kvp;
using bsoncxx::builder::basic::make_document;

int main(int, char**) {
    // The mongocxx::instance constructor and destructor initialize and shut down the driver,
    // respectively. Therefore, a mongocxx::instance must be created before using the driver and
    // must remain alive for as long as the driver is in use.
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};

    auto db = conn["test"];
    try {
        db["restaurants"].drop();
    } catch (const std::exception&) {
        // Collection did not exist.
    }

    // Create a single field index.
    {
        // @begin: cpp-single-field-index
        db["restaurants"].create_index(make_document(kvp("cuisine", 1)), {});
        // @end: cpp-single-field-index
    }

    // Create a compound index.
    {
        db["restaurants"].drop();
        // @begin: cpp-create-compound-index
        db["restaurants"].create_index(make_document(kvp("cuisine", 1), kvp("address.zipcode", -1)),
                                       {});
        // @end: cpp-create-compound-index
    }

    // Create a unique index.
    {
        db["restaurants"].drop();
        // @begin: cpp-create-unique-index
        mongocxx::options::index index_options{};
        index_options.unique(true);
        db["restaurants"].create_index(make_document(kvp("website", 1)), index_options);
        // @end: cpp-create-unique-index
    }

    // Create an index with storage engine options
    {
        db["restaurants"].drop();
        // @begin: cpp-create-wt-options-index
        mongocxx::options::index index_options{};
        std::unique_ptr<mongocxx::options::index::wiredtiger_storage_options> wt_options =
            bsoncxx::stdx::make_unique<mongocxx::options::index::wiredtiger_storage_options>();
        wt_options->config_string("block_allocation=first");
        index_options.storage_options(std::move(wt_options));
        db["restaurants"].create_index(make_document(kvp("cuisine", 1)), index_options);
        // @begin: cpp-create-wt-options-index
    }
}
<|endoftext|>


<commit_before>/* Copyright 2017 - 2022 R. Thomas
 * Copyright 2017 - 2022 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <iterator>
#include <vector>
#include <string>
#include <fstream>
#include <cassert>
#include <sstream>
#include <algorithm>

#include <mbedtls/platform.h>
#include <mbedtls/asn1.h>
#include <mbedtls/error.h>
#include <mbedtls/oid.h>
#include <mbedtls/x509_crt.h>

#include "logging.hpp"

#include "LIEF/BinaryStream/VectorStream.hpp"
#include "LIEF/exception.hpp"
namespace LIEF {

VectorStream::VectorStream(VectorStream&& other) = default;
VectorStream& VectorStream::operator=(VectorStream&& other) = default;

inline void free_names(mbedtls_x509_name& names) {
  mbedtls_x509_name *name_cur;
  name_cur = names.next;
  while (name_cur != nullptr) {
    mbedtls_x509_name *name_prv = name_cur;
    name_cur = name_cur->next;
    mbedtls_free(name_prv);
  }
}

result<VectorStream> VectorStream::from_file(const std::string& file) {
  std::ifstream ifs(file, std::ios::in | std::ios::binary);
  if (!ifs) {
    LIEF_ERR("Can't opent '{}'", file);
    return make_error_code(lief_errors::read_error);
  }

  ifs.unsetf(std::ios::skipws);
  ifs.seekg(0, std::ios::end);
  const size_t size = static_cast<uint64_t>(ifs.tellg());
  ifs.seekg(0, std::ios::beg);
  std::vector<uint8_t> data;
  data.resize(size, 0);
  ifs.read(reinterpret_cast<char*>(data.data()), data.size());
  return VectorStream{std::move(data)};
}

VectorStream::VectorStream(std::vector<uint8_t> data) :
  binary_{std::move(data)},
  size_{binary_.size()}
{
  stype_ = STREAM_TYPE::VECTOR;
}

result<const void*> VectorStream::read_at(uint64_t offset, uint64_t size) const {
  const uint64_t stream_size = this->size();
  if (offset > stream_size || (offset + size) > stream_size) {
    size_t out_size = (offset + size) - stream_size;
    LIEF_DEBUG("Can't read #{:d} bytes at 0x{:04x} (0x{:x} bytes out of bound)", size, offset, out_size);
    return make_error_code(lief_errors::read_error);
  }
  return binary_.data() + offset;
}

result<size_t> VectorStream::asn1_read_tag(int tag) {
  size_t out = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_tag(&p, end, &out, tag);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
    return make_error_code(lief_errors::asn1_bad_tag);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return out;
}

result<size_t> VectorStream::asn1_read_len() {
  size_t len = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_len(&p, end, &len);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return len;
}

result<std::string> VectorStream::asn1_read_alg() {
  mbedtls_asn1_buf alg_oid;
  std::array<char, 256> oid_str = {0};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &alg_oid);
  if (ret <= 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::string(oid_str.data());
}

result<std::string> VectorStream::asn1_read_oid() {
  mbedtls_asn1_buf buf;
  std::array<char, 256> oid_str = {0};

  auto len = asn1_read_tag(MBEDTLS_ASN1_OID);
  if (!len) {
    return len.error();
  }

  buf.len = len.value();
  buf.p   = p();
  buf.tag = MBEDTLS_ASN1_OID;

  int ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &buf);
  if (ret == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
    LIEF_DEBUG("asn1_read_oid: mbedtls_oid_get_numeric_string return MBEDTLS_ERR_OID_BUF_TOO_SMALL");
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(buf.len);
  return std::string(oid_str.data());
}

result<int32_t> VectorStream::asn1_read_int() {
  int32_t value = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_int(&p, end, &value);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return value;
}

result<std::vector<uint8_t>> VectorStream::asn1_read_bitstring() {
  mbedtls_asn1_bitstring bs = {0, 0, nullptr};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_bitstring(&p, end, &bs);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret == MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) {
    increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
    return std::vector<uint8_t>{bs.p, bs.p + bs.len};
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::vector<uint8_t>{bs.p, bs.p + bs.len};
}

result<std::vector<uint8_t>> VectorStream::asn1_read_octet_string() {
  auto tag = asn1_read_tag(MBEDTLS_ASN1_OCTET_STRING);
  if (!tag) {
    return tag.error();
  }
  std::vector<uint8_t> raw = {p(), p() + tag.value()};
  increment_pos(tag.value());
  return raw;
}

result<std::unique_ptr<mbedtls_x509_crt>> VectorStream::asn1_read_cert() {
  std::unique_ptr<mbedtls_x509_crt> ca{new mbedtls_x509_crt{}};
  mbedtls_x509_crt_init(ca.get());

  uint8_t* p               = this->p();
  const uint8_t* end       = this->end();
  const uintptr_t buff_len = reinterpret_cast<uintptr_t>(end) - reinterpret_cast<uintptr_t>(p);

  int ret = mbedtls_x509_crt_parse_der(ca.get(), p, /* buff len */ buff_len);
  if (ret != 0) {
    std::string strerr(1024, 0);
    mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
    LIEF_DEBUG("asn1_read_cert(): {}", strerr);
    return make_error_code(lief_errors::read_error);
  }
  if (ca->raw.len <= 0) {
    return make_error_code(lief_errors::read_error);
  }
  increment_pos(ca->raw.len);
  return ca;
}

result<std::string> VectorStream::x509_read_names() {
  mbedtls_x509_name name;
  std::memset(&name, 0, sizeof(name));

  auto tag = asn1_read_tag(/* Name */
                           MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
  if (!tag) {
    LIEF_INFO("Wrong tag: 0x{:x} for x509_read_names (pos: {:d})", *peek<uint8_t>(), pos());
    return tag.error();
  }

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = p + tag.value();
  int ret = mbedtls_x509_get_name(&p, end, &name);
  if (ret != 0) {
    free_names(name);
    LIEF_DEBUG("mbedtls_x509_get_name failed with {:d}", ret);
    return make_error_code(lief_errors::read_error);
  }
  std::array<char, 1024> buffer = {0};
  ret = mbedtls_x509_dn_gets(buffer.data(), buffer.size(), &name);
  free_names(name);

  if (ret < 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::string(buffer.data());
}

result<std::vector<uint8_t>> VectorStream::x509_read_serial() {
  mbedtls_x509_buf serial;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_x509_get_serial(&p, end, &serial);

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::vector<uint8_t>{serial.p, serial.p + serial.len};
}

result<std::unique_ptr<mbedtls_x509_time>> VectorStream::x509_read_time() {
  std::unique_ptr<mbedtls_x509_time> tm{new mbedtls_x509_time{}};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_x509_get_time(&p, end, tm.get());

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return tm;
}

const std::vector<uint8_t>& VectorStream::content() const {
  return binary_;
}

bool VectorStream::classof(const BinaryStream& stream) {
  return stream.type() == STREAM_TYPE::VECTOR;
}
}

<commit_msg>Add missing array header<commit_after>/* Copyright 2017 - 2022 R. Thomas
 * Copyright 2017 - 2022 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <array>
#include <iterator>
#include <vector>
#include <string>
#include <fstream>
#include <cassert>
#include <sstream>
#include <algorithm>

#include <mbedtls/platform.h>
#include <mbedtls/asn1.h>
#include <mbedtls/error.h>
#include <mbedtls/oid.h>
#include <mbedtls/x509_crt.h>

#include "logging.hpp"

#include "LIEF/BinaryStream/VectorStream.hpp"
#include "LIEF/exception.hpp"
namespace LIEF {

VectorStream::VectorStream(VectorStream&& other) = default;
VectorStream& VectorStream::operator=(VectorStream&& other) = default;

inline void free_names(mbedtls_x509_name& names) {
  mbedtls_x509_name *name_cur;
  name_cur = names.next;
  while (name_cur != nullptr) {
    mbedtls_x509_name *name_prv = name_cur;
    name_cur = name_cur->next;
    mbedtls_free(name_prv);
  }
}

result<VectorStream> VectorStream::from_file(const std::string& file) {
  std::ifstream ifs(file, std::ios::in | std::ios::binary);
  if (!ifs) {
    LIEF_ERR("Can't opent '{}'", file);
    return make_error_code(lief_errors::read_error);
  }

  ifs.unsetf(std::ios::skipws);
  ifs.seekg(0, std::ios::end);
  const size_t size = static_cast<uint64_t>(ifs.tellg());
  ifs.seekg(0, std::ios::beg);
  std::vector<uint8_t> data;
  data.resize(size, 0);
  ifs.read(reinterpret_cast<char*>(data.data()), data.size());
  return VectorStream{std::move(data)};
}

VectorStream::VectorStream(std::vector<uint8_t> data) :
  binary_{std::move(data)},
  size_{binary_.size()}
{
  stype_ = STREAM_TYPE::VECTOR;
}

result<const void*> VectorStream::read_at(uint64_t offset, uint64_t size) const {
  const uint64_t stream_size = this->size();
  if (offset > stream_size || (offset + size) > stream_size) {
    size_t out_size = (offset + size) - stream_size;
    LIEF_DEBUG("Can't read #{:d} bytes at 0x{:04x} (0x{:x} bytes out of bound)", size, offset, out_size);
    return make_error_code(lief_errors::read_error);
  }
  return binary_.data() + offset;
}

result<size_t> VectorStream::asn1_read_tag(int tag) {
  size_t out = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_tag(&p, end, &out, tag);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
    return make_error_code(lief_errors::asn1_bad_tag);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return out;
}

result<size_t> VectorStream::asn1_read_len() {
  size_t len = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_len(&p, end, &len);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return len;
}

result<std::string> VectorStream::asn1_read_alg() {
  mbedtls_asn1_buf alg_oid;
  std::array<char, 256> oid_str = {0};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &alg_oid);
  if (ret <= 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::string(oid_str.data());
}

result<std::string> VectorStream::asn1_read_oid() {
  mbedtls_asn1_buf buf;
  std::array<char, 256> oid_str = {0};

  auto len = asn1_read_tag(MBEDTLS_ASN1_OID);
  if (!len) {
    return len.error();
  }

  buf.len = len.value();
  buf.p   = p();
  buf.tag = MBEDTLS_ASN1_OID;

  int ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &buf);
  if (ret == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
    LIEF_DEBUG("asn1_read_oid: mbedtls_oid_get_numeric_string return MBEDTLS_ERR_OID_BUF_TOO_SMALL");
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(buf.len);
  return std::string(oid_str.data());
}

result<int32_t> VectorStream::asn1_read_int() {
  int32_t value = 0;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_int(&p, end, &value);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return value;
}

result<std::vector<uint8_t>> VectorStream::asn1_read_bitstring() {
  mbedtls_asn1_bitstring bs = {0, 0, nullptr};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_asn1_get_bitstring(&p, end, &bs);

  if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) {
    return make_error_code(lief_errors::read_out_of_bound);
  }

  if (ret == MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) {
    increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
    return std::vector<uint8_t>{bs.p, bs.p + bs.len};
  }

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::vector<uint8_t>{bs.p, bs.p + bs.len};
}

result<std::vector<uint8_t>> VectorStream::asn1_read_octet_string() {
  auto tag = asn1_read_tag(MBEDTLS_ASN1_OCTET_STRING);
  if (!tag) {
    return tag.error();
  }
  std::vector<uint8_t> raw = {p(), p() + tag.value()};
  increment_pos(tag.value());
  return raw;
}

result<std::unique_ptr<mbedtls_x509_crt>> VectorStream::asn1_read_cert() {
  std::unique_ptr<mbedtls_x509_crt> ca{new mbedtls_x509_crt{}};
  mbedtls_x509_crt_init(ca.get());

  uint8_t* p               = this->p();
  const uint8_t* end       = this->end();
  const uintptr_t buff_len = reinterpret_cast<uintptr_t>(end) - reinterpret_cast<uintptr_t>(p);

  int ret = mbedtls_x509_crt_parse_der(ca.get(), p, /* buff len */ buff_len);
  if (ret != 0) {
    std::string strerr(1024, 0);
    mbedtls_strerror(ret, const_cast<char*>(strerr.data()), strerr.size());
    LIEF_DEBUG("asn1_read_cert(): {}", strerr);
    return make_error_code(lief_errors::read_error);
  }
  if (ca->raw.len <= 0) {
    return make_error_code(lief_errors::read_error);
  }
  increment_pos(ca->raw.len);
  return ca;
}

result<std::string> VectorStream::x509_read_names() {
  mbedtls_x509_name name;
  std::memset(&name, 0, sizeof(name));

  auto tag = asn1_read_tag(/* Name */
                           MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
  if (!tag) {
    LIEF_INFO("Wrong tag: 0x{:x} for x509_read_names (pos: {:d})", *peek<uint8_t>(), pos());
    return tag.error();
  }

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = p + tag.value();
  int ret = mbedtls_x509_get_name(&p, end, &name);
  if (ret != 0) {
    free_names(name);
    LIEF_DEBUG("mbedtls_x509_get_name failed with {:d}", ret);
    return make_error_code(lief_errors::read_error);
  }
  std::array<char, 1024> buffer = {0};
  ret = mbedtls_x509_dn_gets(buffer.data(), buffer.size(), &name);
  free_names(name);

  if (ret < 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::string(buffer.data());
}

result<std::vector<uint8_t>> VectorStream::x509_read_serial() {
  mbedtls_x509_buf serial;

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_x509_get_serial(&p, end, &serial);

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return std::vector<uint8_t>{serial.p, serial.p + serial.len};
}

result<std::unique_ptr<mbedtls_x509_time>> VectorStream::x509_read_time() {
  std::unique_ptr<mbedtls_x509_time> tm{new mbedtls_x509_time{}};

  const uint8_t* cur_p = p();
  uint8_t* p           = this->p();
  const uint8_t* end   = this->end();

  int ret = mbedtls_x509_get_time(&p, end, tm.get());

  if (ret != 0) {
    return make_error_code(lief_errors::read_error);
  }

  increment_pos(reinterpret_cast<uintptr_t>(p) - reinterpret_cast<uintptr_t>(cur_p));
  return tm;
}

const std::vector<uint8_t>& VectorStream::content() const {
  return binary_;
}

bool VectorStream::classof(const BinaryStream& stream) {
  return stream.type() == STREAM_TYPE::VECTOR;
}
}

<|endoftext|>


<commit_before><commit_msg>fixing BoxROI_test<commit_after><|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS a11ysep (1.1.2); FILE ADDED 2006/10/04 20:11:17 fs 1.1.2.4: adjusted include protection names 2006/10/04 19:58:00 fs 1.1.2.3: MANUAL RESYNC m130->m185: file was changed in MWS, but has been moved herein in CWS 2005/09/28 11:39:37 fs 1.1.2.2: manual resync (files have been moved herein from another location): licence change 2005/03/07 08:27:27 fs 1.1.2.1: #i44293# moved implementations herein from svtools module<commit_after><|endoftext|>


<commit_before><commit_msg>Need to specify boost::python::arg<commit_after><|endoftext|>


<commit_before>#include <vector>
#include <cstdint>
#include <sstream>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>

#include "Tools/general_utils.h"
#include "Tools/Exception/exception.hpp"
#include "Tools/types.h"
#include "Tools/date.h"

#include "Launcher/Launcher.hpp"
#include "Launcher/Code/BCH/BCH.hpp"
#include "Launcher/Code/LDPC/LDPC.hpp"
#include "Launcher/Code/Polar/Polar.hpp"
#include "Launcher/Code/RA/RA.hpp"
#include "Launcher/Code/Repetition/Repetition.hpp"
#include "Launcher/Code/RSC/RSC.hpp"
#include "Launcher/Code/Turbo/Turbo.hpp"
#include "Launcher/Code/Uncoded/Uncoded.hpp"
#include "Launcher/Simulation/BFER_ite.hpp"
#include "Launcher/Simulation/BFER_std.hpp"
#include "Launcher/Simulation/EXIT.hpp"

#include "Launcher.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Launcher::name   = "Launcher";
const std::string aff3ct::factory::Launcher::prefix = "lch";

template <typename B, typename R, typename Q, typename QD>
launcher::Launcher* Launcher
::build_exit(const parameters &params, const int argc, const char **argv)
{
	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}

namespace aff3ct
{
namespace factory
{
#if defined(MULTI_PREC) || defined(PREC_32_BIT)
template <>
launcher::Launcher* Launcher
::build_exit<int32_t, float, float, float>(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
		if (params.sim_type == "EXIT")
			return new launcher::Polar<launcher::EXIT<int32_t,float>,int32_t,float,float>(argc, argv);

	if (params.cde_type == "RSC")
		if (params.sim_type == "EXIT")
			return new launcher::RSC<launcher::EXIT<int32_t,float>,int32_t,float,float,float>(argc, argv);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}
#endif

#if defined(MULTI_PREC) || defined(PREC_64_BIT)
template <>
launcher::Launcher* Launcher
::build_exit<int64_t, double, double, double>(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
		if (params.sim_type == "EXIT")
			return new launcher::Polar<launcher::EXIT<int64_t,double>,int64_t,double,double>(argc, argv);

	if (params.cde_type == "RSC")
		if (params.sim_type == "EXIT")
			return new launcher::RSC<launcher::EXIT<int64_t,double>,int64_t,double,double,double>(argc, argv);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}
#endif
}
}

template <typename B, typename R, typename Q, typename QD>
launcher::Launcher* Launcher
::build(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
	{
		if (params.sim_type == "BFER")
			return new launcher::Polar<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::Polar<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "RSC")
	{
		if (params.sim_type == "BFER")
			return new launcher::RSC<launcher::BFER_std<B,R,Q>,B,R,Q,QD>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::RSC<launcher::BFER_ite<B,R,Q>,B,R,Q,QD>(argc, argv);
	}

	if (params.cde_type == "TURBO")
	{
		if (params.sim_type == "BFER")
			return new launcher::Turbo<launcher::BFER_std<B,R,Q>,B,R,Q,QD>(argc, argv);
	}

	if (params.cde_type == "REPETITION")
	{
		if (params.sim_type == "BFER")
			return new launcher::Repetition<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "BCH")
	{
		if (params.sim_type == "BFER")
			return new launcher::BCH<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "RA")
	{
		if (params.sim_type == "BFER")
			return new launcher::RA<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "LDPC")
	{
		if (params.sim_type == "BFER")
			return new launcher::LDPC<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::LDPC<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "UNCODED")
	{
		if (params.sim_type == "BFER")
			return new launcher::Uncoded<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::Uncoded<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	return build_exit<B,R,Q,QD>(params, argc, argv);
}

void Launcher::build_args(arg_map &req_args, arg_map &opt_args, const std::string p)
{
	req_args[{p+"-cde-type", "C"}] =
		{"string",
		 "select the code type you want to use.",
		 "POLAR, TURBO, LDPC, REPETITION, RA, RSC, BCH, UNCODED"};

	opt_args[{p+"-type"}] =
		{"string",
		 "select the type of simulation to launch (default is BFER).",
		 "BFER, BFERI, EXIT, GEN"};

#ifdef MULTI_PREC
	opt_args[{p+"-prec", "p"}] =
		{"positive_int",
		 "the simulation precision in bit.",
		 "8, 16, 32"};

#if defined(__x86_64) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__)
	opt_args[{p+"-prec", "p"}][2] += ", 64";
#endif
#endif

	opt_args[{"help", "h"}] =
		{"",
		 "print this help."};

	opt_args[{"version", "v"}] =
		{"",
		 "print informations about the version of the code."};
}

void Launcher::store_args(const arg_val_map &vals, parameters &params, const std::string p)
{
	if(exist(vals, {p+"-cde-type",  "C"})) params.cde_type        = vals.at({p+"-cde-type", "C"}); // required
	if(exist(vals, {p+"-type"          })) params.sim_type        = vals.at({p+"-type"         });
	if(exist(vals, {"help",         "h"})) params.display_help    = true;
	if(exist(vals, {"version",      "v"})) params.display_version = true;

#ifdef MULTI_PREC
	if(exist(vals, {"sim-prec", "p"})) params.sim_prec = std::stoi(vals.at({"sim-prec", "p"}));
#endif
}

void Launcher::make_header(params_list& head_sim, const parameters& params, const bool full)
{
	std::unordered_map<std::type_index,std::string> type_names;
	// define type names
	type_names[typeid(int8_t )] = "int8";
	type_names[typeid(int16_t)] = "int16";
	type_names[typeid(int32_t)] = "int32";
	type_names[typeid(int64_t)] = "int64";
	type_names[typeid(float  )] = "float32";
	type_names[typeid(double )] = "float64";

	head_sim.push_back(std::make_pair("Type", params.sim_type));

	std::type_index id_B = typeid(int32_t), id_R = typeid(float), id_Q = typeid(float);
#ifdef MULTI_PREC
	switch (params.sim_prec)
	{
		case 8:
			id_B = typeid(B_8);
			id_R = typeid(R_8);
			id_Q = typeid(Q_8);
		break;

		case 16:
			id_B = typeid(B_16);
			id_R = typeid(R_16);
			id_Q = typeid(Q_16);
		break;

		case 32:
			id_B = typeid(B_32);
			id_R = typeid(R_32);
			id_Q = typeid(Q_32);
		break;

#if defined(__x86_64) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__)
		case 64:
			id_B = typeid(B_64);
			id_R = typeid(R_64);
			id_Q = typeid(Q_64);
		break;
#endif
		default :
			std::stringstream message;
			message << "Unsupported bit precision: " << params.sim_prec << ").";
			throw tools::invalid_argument(__FILE__, __LINE__, __func__, message.str());
		break;
	}
#else
	id_B = typeid(B);
	id_R = typeid(R);
	id_Q = typeid(Q);
#endif

	head_sim.push_back(std::make_pair("Type of bits",  type_names[id_B]));
	head_sim.push_back(std::make_pair("Type of reals", type_names[id_R]));
	if (std::is_integral<Q>::value)
		head_sim.push_back(std::make_pair("Type of quant. reals", type_names[id_Q]));

	using namespace date;
	std::stringstream date;
	date << std::chrono::system_clock::now();
	auto split_date = tools::string_split(date.str(), '.');
	head_sim.push_back(std::make_pair("Date (UTC)", split_date[0]));

	head_sim.push_back(std::make_pair("Code type (C)", params.cde_type));
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_8 ,R_8 ,Q_8 ,QD_8 >(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_16,R_16,Q_16,QD_16>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_32,R_32,Q_32,QD_32>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_64,R_64,Q_64,QD_64>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
#else
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B,R,Q,QD>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
#endif
// ==================================================================================== explicit template instantiation
<commit_msg>Fix a potential bug in the Launcher factory.<commit_after>#include <vector>
#include <cstdint>
#include <sstream>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>

#include "Tools/general_utils.h"
#include "Tools/Exception/exception.hpp"
#include "Tools/types.h"
#include "Tools/date.h"

#include "Launcher/Launcher.hpp"
#include "Launcher/Code/BCH/BCH.hpp"
#include "Launcher/Code/LDPC/LDPC.hpp"
#include "Launcher/Code/Polar/Polar.hpp"
#include "Launcher/Code/RA/RA.hpp"
#include "Launcher/Code/Repetition/Repetition.hpp"
#include "Launcher/Code/RSC/RSC.hpp"
#include "Launcher/Code/Turbo/Turbo.hpp"
#include "Launcher/Code/Uncoded/Uncoded.hpp"
#include "Launcher/Simulation/BFER_ite.hpp"
#include "Launcher/Simulation/BFER_std.hpp"
#include "Launcher/Simulation/EXIT.hpp"

#include "Launcher.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Launcher::name   = "Launcher";
const std::string aff3ct::factory::Launcher::prefix = "lch";

template <typename B, typename R, typename Q, typename QD>
launcher::Launcher* Launcher
::build_exit(const parameters &params, const int argc, const char **argv)
{
	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}

namespace aff3ct
{
namespace factory
{
#if defined(MULTI_PREC) || defined(PREC_32_BIT)
template <>
launcher::Launcher* Launcher
::build_exit<int32_t, float, float, float>(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
		if (params.sim_type == "EXIT")
			return new launcher::Polar<launcher::EXIT<int32_t,float>,int32_t,float,float>(argc, argv);

	if (params.cde_type == "RSC")
		if (params.sim_type == "EXIT")
			return new launcher::RSC<launcher::EXIT<int32_t,float>,int32_t,float,float,float>(argc, argv);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}
#endif

#if defined(MULTI_PREC) || defined(PREC_64_BIT)
template <>
launcher::Launcher* Launcher
::build_exit<int64_t, double, double, double>(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
		if (params.sim_type == "EXIT")
			return new launcher::Polar<launcher::EXIT<int64_t,double>,int64_t,double,double>(argc, argv);

	if (params.cde_type == "RSC")
		if (params.sim_type == "EXIT")
			return new launcher::RSC<launcher::EXIT<int64_t,double>,int64_t,double,double,double>(argc, argv);

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__, "Unsupported code/simulation pair.");
}
#endif
}
}

template <typename B, typename R, typename Q, typename QD>
launcher::Launcher* Launcher
::build(const parameters &params, const int argc, const char **argv)
{
	if (params.cde_type == "POLAR")
	{
		if (params.sim_type == "BFER")
			return new launcher::Polar<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::Polar<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "RSC")
	{
		if (params.sim_type == "BFER")
			return new launcher::RSC<launcher::BFER_std<B,R,Q>,B,R,Q,QD>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::RSC<launcher::BFER_ite<B,R,Q>,B,R,Q,QD>(argc, argv);
	}

	if (params.cde_type == "TURBO")
	{
		if (params.sim_type == "BFER")
			return new launcher::Turbo<launcher::BFER_std<B,R,Q>,B,R,Q,QD>(argc, argv);
	}

	if (params.cde_type == "REPETITION")
	{
		if (params.sim_type == "BFER")
			return new launcher::Repetition<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "BCH")
	{
		if (params.sim_type == "BFER")
			return new launcher::BCH<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "RA")
	{
		if (params.sim_type == "BFER")
			return new launcher::RA<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "LDPC")
	{
		if (params.sim_type == "BFER")
			return new launcher::LDPC<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::LDPC<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	if (params.cde_type == "UNCODED")
	{
		if (params.sim_type == "BFER")
			return new launcher::Uncoded<launcher::BFER_std<B,R,Q>,B,R,Q>(argc, argv);
		else if (params.sim_type == "BFERI")
			return new launcher::Uncoded<launcher::BFER_ite<B,R,Q>,B,R,Q>(argc, argv);
	}

	return build_exit<B,R,Q,QD>(params, argc, argv);
}

void Launcher::build_args(arg_map &req_args, arg_map &opt_args, const std::string p)
{
	req_args[{p+"-cde-type", "C"}] =
		{"string",
		 "select the code type you want to use.",
		 "POLAR, TURBO, LDPC, REPETITION, RA, RSC, BCH, UNCODED"};

	opt_args[{p+"-type"}] =
		{"string",
		 "select the type of simulation to launch (default is BFER).",
		 "BFER, BFERI, EXIT, GEN"};

#ifdef MULTI_PREC
	opt_args[{p+"-prec", "p"}] =
		{"positive_int",
		 "the simulation precision in bit.",
		 "8, 16, 32"};

#if defined(__x86_64) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__)
	opt_args[{p+"-prec", "p"}][2] += ", 64";
#endif
#endif

	opt_args[{"help", "h"}] =
		{"",
		 "print this help."};

	opt_args[{"version", "v"}] =
		{"",
		 "print informations about the version of the code."};
}

void Launcher::store_args(const arg_val_map &vals, parameters &params, const std::string p)
{
	if(exist(vals, {p+"-cde-type",  "C"})) params.cde_type        = vals.at({p+"-cde-type", "C"}); // required
	if(exist(vals, {p+"-type"          })) params.sim_type        = vals.at({p+"-type"         });
	if(exist(vals, {"help",         "h"})) params.display_help    = true;
	if(exist(vals, {"version",      "v"})) params.display_version = true;

#ifdef MULTI_PREC
	if(exist(vals, {p+"-prec", "p"})) params.sim_prec = std::stoi(vals.at({p+"-prec", "p"}));
#endif
}

void Launcher::make_header(params_list& head_sim, const parameters& params, const bool full)
{
	std::unordered_map<std::type_index,std::string> type_names;
	// define type names
	type_names[typeid(int8_t )] = "int8";
	type_names[typeid(int16_t)] = "int16";
	type_names[typeid(int32_t)] = "int32";
	type_names[typeid(int64_t)] = "int64";
	type_names[typeid(float  )] = "float32";
	type_names[typeid(double )] = "float64";

	head_sim.push_back(std::make_pair("Type", params.sim_type));

	std::type_index id_B = typeid(int32_t), id_R = typeid(float), id_Q = typeid(float);
#ifdef MULTI_PREC
	switch (params.sim_prec)
	{
		case 8:
			id_B = typeid(B_8);
			id_R = typeid(R_8);
			id_Q = typeid(Q_8);
		break;

		case 16:
			id_B = typeid(B_16);
			id_R = typeid(R_16);
			id_Q = typeid(Q_16);
		break;

		case 32:
			id_B = typeid(B_32);
			id_R = typeid(R_32);
			id_Q = typeid(Q_32);
		break;

#if defined(__x86_64) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__)
		case 64:
			id_B = typeid(B_64);
			id_R = typeid(R_64);
			id_Q = typeid(Q_64);
		break;
#endif
		default :
			std::stringstream message;
			message << "Unsupported bit precision: " << params.sim_prec << ").";
			throw tools::invalid_argument(__FILE__, __LINE__, __func__, message.str());
		break;
	}
#else
	id_B = typeid(B);
	id_R = typeid(R);
	id_Q = typeid(Q);
#endif

	head_sim.push_back(std::make_pair("Type of bits",  type_names[id_B]));
	head_sim.push_back(std::make_pair("Type of reals", type_names[id_R]));
	if (std::is_integral<Q>::value)
		head_sim.push_back(std::make_pair("Type of quant. reals", type_names[id_Q]));

	using namespace date;
	std::stringstream date;
	date << std::chrono::system_clock::now();
	auto split_date = tools::string_split(date.str(), '.');
	head_sim.push_back(std::make_pair("Date (UTC)", split_date[0]));

	head_sim.push_back(std::make_pair("Code type (C)", params.cde_type));
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_8 ,R_8 ,Q_8 ,QD_8 >(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_16,R_16,Q_16,QD_16>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_32,R_32,Q_32,QD_32>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B_64,R_64,Q_64,QD_64>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
#else
template aff3ct::launcher::Launcher* aff3ct::factory::Launcher::build<B,R,Q,QD>(const aff3ct::factory::Launcher::parameters&, const int, const char**);
#endif
// ==================================================================================== explicit template instantiation
<|endoftext|>


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

#include "ActionBinding.h"
#include "AnimationBinding.h"
#include "ApplicationRootBinding.h"
#include "ArrayPlugBinding.h"
#include "BoxPlugBinding.h"
#include "CompoundDataPlugBinding.h"
#include "CompoundNumericPlugBinding.h"
#include "ConnectionBinding.h"
#include "ContextBinding.h"
#include "ContextProcessorBinding.h"
#include "DirtyPropagationScopeBinding.h"
#include "DotBinding.h"
#include "ExpressionBinding.h"
#include "GraphComponentBinding.h"
#include "ProcessMessageHandlerBinding.h"
#include "MetadataAlgoBinding.h"
#include "MetadataBinding.h"
#include "MonitorBinding.h"
#include "NodeAlgoBinding.h"
#include "NodeBinding.h"
#include "NumericPlugBinding.h"
#include "ParallelAlgoBinding.h"
#include "PathBinding.h"
#include "PathFilterBinding.h"
#include "PlugAlgoBinding.h"
#include "PlugBinding.h"
#include "ProcessBinding.h"
#include "RandomBinding.h"
#include "ScriptNodeBinding.h"
#include "SerialisationBinding.h"
#include "SetBinding.h"
#include "SignalBinding.h"
#include "SplinePlugBinding.h"
#include "SpreadsheetBinding.h"
#include "StringPlugBinding.h"
#include "SubGraphBinding.h"
#include "SwitchBinding.h"
#include "Transform2DPlugBinding.h"
#include "TransformPlugBinding.h"
#include "TypedObjectPlugBinding.h"
#include "TypedPlugBinding.h"
#include "UndoScopeBinding.h"
#include "ValuePlugBinding.h"
#include "NameValuePlugBinding.h"
#include "ShufflesBinding.h"

#include "GafferBindings/DependencyNodeBinding.h"

#include "Gaffer/Backdrop.h"

#ifdef __linux__
#include <sys/prctl.h>
#endif

using namespace boost::python;
using namespace Gaffer;
using namespace GafferModule;
using namespace GafferBindings;

namespace
{

bool isDebug()
{
#ifdef NDEBUG
	return false;
#else
	return true;
#endif
}

// This is documented as being for the use of extension
// modules, but then isn't declared in the Python headers,
// so we declare it ourselves.
extern "C" void Py_GetArgcArgv( int *argc, char ***argv );

void clobberArgv()
{
	// Get the original argc/argv that was passed to
	// `main()`. We will modify this in place.
	int argc;
	char **argv;
	Py_GetArgcArgv( &argc, &argv );

	// A typical command line looks like this :
	//
	// `gaffer arg1 arg2 arg3`
	//
	// But will look like this once the wrapper
	// has launched Gaffer via Python :
	//
	// `python gaffer.py arg1 arg2 arg3`
	//
	// Replace the `python` bit with `gaffer` and
	// shuffle all the arguments around so that
	// the `gaffer.py` argument disappears and we
	// get back to the original.
	char *end = argv[argc-1] + strlen( argv[argc-1] );
	strncpy( argv[0], "gaffer", strlen( argv[0] ) );
	strncpy( argv[1], "", strlen( argv[1] ) );
	char *emptyString = argv[1];
	for( int i = 1; i < argc - 1; ++i )
	{
		argv[i] = argv[i+1];
	}
	argv[argc-1] = emptyString;

	// We've just shuffled the pointers so far, but
	// in practice the original strings were contiguous
	// in the same chunk of memory, and `ps` uses that fact
	// rather than actually use the argv pointers. See
	// https://stackoverflow.com/a/23400588.
	//
	// Pack everything back down so `ps` sees what it
	// expects.
	char *c = argv[0];
	for( int i = 0; i < argc - 1; ++i )
	{
		const size_t l = strlen( argv[i] ) + 1;
		memmove( c, argv[i], l );
		argv[i] = c;
		c += l;
	}
	argv[argc-1] = c;
	memset( c, 0, end - c );
}

void nameProcess()
{
	// Some things (for instance, `ps` in default mode) look at `argv` to get
	// the name.
	clobberArgv();
	// Others (for instance, `top` in default mode) use other methods.
	// Cater to everyone as best we can.
#ifdef __linux__
	prctl( PR_SET_NAME, "gaffer", 0, 0, 0 );
#endif
}

} // namespace

BOOST_PYTHON_MODULE( _Gaffer )
{

	bindConnection();
	bindSignal();
	bindGraphComponent();
	bindContext();
	bindSerialisation();
	bindNode();
	bindPlug();
	bindValuePlug();
	bindNumericPlug();
	bindTypedPlug();
	bindStringPlug();
	bindTypedObjectPlug();
	bindScriptNode();
	bindApplicationRoot();
	bindSet();
	bindDirtyPropagationScope();
	bindUndoScope();
	bindCompoundNumericPlug();
	bindSplinePlug();
	bindBoxPlug();
	bindExpression();
	bindTransformPlug();
	bindTransform2DPlug();
	bindCompoundDataPlug();
	bindRandom();
	bindSubGraph();
	bindAction();
	bindArrayPlug();
	bindMetadata();
	bindDot();
	bindPath();
	bindPathFilter();
	bindAnimation();
	bindMonitor();
	bindMetadataAlgo();
	bindSwitch();
	bindPlugAlgo();
	bindParallelAlgo();
	bindContextProcessor();
	bindProcessMessageHandler();
	bindNameValuePlug();
	bindProcess();
	bindSpreadsheet();
	bindNodeAlgo();
	bindShuffles();

	NodeClass<Backdrop>();

	def( "isDebug", &isDebug );

	def( "_nameProcess", &nameProcess );

	// Various parts of gaffer create new threads from C++, and those
	// threads may call back into Python via wrapped classes at any time.
	// We must prepare Python for this by calling PyEval_InitThreads().

	PyEval_InitThreads();

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

#include "ActionBinding.h"
#include "AnimationBinding.h"
#include "ApplicationRootBinding.h"
#include "ArrayPlugBinding.h"
#include "BoxPlugBinding.h"
#include "CompoundDataPlugBinding.h"
#include "CompoundNumericPlugBinding.h"
#include "ConnectionBinding.h"
#include "ContextBinding.h"
#include "ContextProcessorBinding.h"
#include "DirtyPropagationScopeBinding.h"
#include "DotBinding.h"
#include "ExpressionBinding.h"
#include "GraphComponentBinding.h"
#include "ProcessMessageHandlerBinding.h"
#include "MetadataAlgoBinding.h"
#include "MetadataBinding.h"
#include "MonitorBinding.h"
#include "NodeAlgoBinding.h"
#include "NodeBinding.h"
#include "NumericPlugBinding.h"
#include "ParallelAlgoBinding.h"
#include "PathBinding.h"
#include "PathFilterBinding.h"
#include "PlugAlgoBinding.h"
#include "PlugBinding.h"
#include "ProcessBinding.h"
#include "RandomBinding.h"
#include "ScriptNodeBinding.h"
#include "SerialisationBinding.h"
#include "SetBinding.h"
#include "SignalBinding.h"
#include "SplinePlugBinding.h"
#include "SpreadsheetBinding.h"
#include "StringPlugBinding.h"
#include "SubGraphBinding.h"
#include "SwitchBinding.h"
#include "Transform2DPlugBinding.h"
#include "TransformPlugBinding.h"
#include "TypedObjectPlugBinding.h"
#include "TypedPlugBinding.h"
#include "UndoScopeBinding.h"
#include "ValuePlugBinding.h"
#include "NameValuePlugBinding.h"
#include "ShufflesBinding.h"

#include "GafferBindings/DependencyNodeBinding.h"

#include "Gaffer/Backdrop.h"

#ifdef __linux__
#include <sys/prctl.h>
#endif

using namespace boost::python;
using namespace Gaffer;
using namespace GafferModule;
using namespace GafferBindings;

namespace
{

bool isDebug()
{
#ifdef NDEBUG
	return false;
#else
	return true;
#endif
}

int g_argc = 0;
char **g_argv = nullptr;

int storeArgcArgv( int argc, char **argv, char **env )
{
	g_argc = argc;
	g_argv = argv;
	return 0;
}

void clobberArgv()
{
	if( g_argc < 2 )
	{
		return;
	}

	// A typical command line looks like this :
	//
	// `gaffer arg1 arg2 arg3`
	//
	// But will look like this once the wrapper
	// has launched Gaffer via Python :
	//
	// `python gaffer.py arg1 arg2 arg3`
	//
	// Replace the `python` bit with `gaffer` and
	// shuffle all the arguments around so that
	// the `gaffer.py` argument disappears and we
	// get back to the original.
	char *end = g_argv[g_argc-1] + strlen( g_argv[g_argc-1] );
	strncpy( g_argv[0], "gaffer", strlen( g_argv[0] ) );
	strncpy( g_argv[1], "", strlen( g_argv[1] ) );
	char *emptyString = g_argv[1];
	for( int i = 1; i < g_argc - 1; ++i )
	{
		g_argv[i] = g_argv[i+1];
	}
	g_argv[g_argc-1] = emptyString;

	// We've just shuffled the pointers so far, but
	// in practice the original strings were contiguous
	// in the same chunk of memory, and `ps` uses that fact
	// rather than actually use the argv pointers. See
	// https://stackoverflow.com/a/23400588.
	//
	// Pack everything back down so `ps` sees what it
	// expects.
	char *c = g_argv[0];
	for( int i = 0; i < g_argc - 1; ++i )
	{
		const size_t l = strlen( g_argv[i] ) + 1;
		memmove( c, g_argv[i], l );
		g_argv[i] = c;
		c += l;
	}
	g_argv[g_argc-1] = c;
	memset( c, 0, end - c );
}

void nameProcess()
{
	// Some things (for instance, `ps` in default mode) look at `argv` to get
	// the name.
	clobberArgv();
	// Others (for instance, `top` in default mode) use other methods.
	// Cater to everyone as best we can.
#ifdef __linux__
	prctl( PR_SET_NAME, "gaffer", 0, 0, 0 );
#endif
}

} // namespace

// Arrange for `storeArgcArgv()` to be called when our module loads,
// so we can stash the original values for `argc` and `argv`.
// In Python 2 we could simply use `Py_GetArgcArgv()` instead, but
// in Python 3 that gives us a mangled copy which is of no use.
#if  defined( __APPLE__ )
__attribute__( ( section( "__DATA,__mod_init_func" ) ) ) decltype( storeArgcArgv ) *g_initArgcArgv = storeArgcArgv;
#elif defined( __linux__ )
__attribute__( ( section( ".init_array" ) ) ) decltype( storeArgcArgv ) *g_initArgcArgv = storeArgcArgv;
#endif

BOOST_PYTHON_MODULE( _Gaffer )
{

	bindConnection();
	bindSignal();
	bindGraphComponent();
	bindContext();
	bindSerialisation();
	bindNode();
	bindPlug();
	bindValuePlug();
	bindNumericPlug();
	bindTypedPlug();
	bindStringPlug();
	bindTypedObjectPlug();
	bindScriptNode();
	bindApplicationRoot();
	bindSet();
	bindDirtyPropagationScope();
	bindUndoScope();
	bindCompoundNumericPlug();
	bindSplinePlug();
	bindBoxPlug();
	bindExpression();
	bindTransformPlug();
	bindTransform2DPlug();
	bindCompoundDataPlug();
	bindRandom();
	bindSubGraph();
	bindAction();
	bindArrayPlug();
	bindMetadata();
	bindDot();
	bindPath();
	bindPathFilter();
	bindAnimation();
	bindMonitor();
	bindMetadataAlgo();
	bindSwitch();
	bindPlugAlgo();
	bindParallelAlgo();
	bindContextProcessor();
	bindProcessMessageHandler();
	bindNameValuePlug();
	bindProcess();
	bindSpreadsheet();
	bindNodeAlgo();
	bindShuffles();

	NodeClass<Backdrop>();

	def( "isDebug", &isDebug );

	def( "_nameProcess", &nameProcess );

	// Various parts of gaffer create new threads from C++, and those
	// threads may call back into Python via wrapped classes at any time.
	// We must prepare Python for this by calling PyEval_InitThreads().

	PyEval_InitThreads();

}
<|endoftext|>


<commit_before>#pragma once

#include "numerics/polynomial_evaluators.hpp"

#include <tuple>

namespace principia {
namespace numerics {
namespace internal_polynomial_evaluators {

namespace {

// Greatest power of 2 less than or equal to n.  8 -> 8, 7 -> 4.
constexpr int FloorOfPowerOf2(int const n) {
  return n == 0 ? 0 : n == 1 ? 1 : FloorOfPowerOf2(n >> 1) << 1;
}

// Ceiling log2 of n.  8 -> 3, 7 -> 2.
constexpr int CeilingLog2(int const n) {
  return n == 1 ? 0 : CeilingLog2(n >> 1) + 1;
}

}  // namespace

// Generator for repeated squaring:
//   SquareGenerator<Length, 0>::Type is Exponentiation<Length, 2>
//   SquareGenerator<Length, 1>::Type is Exponentiation<Length, 4>
//   SquareGenerator<Length, n>::Type is Exponentiation<Length, 2^(n + 1)>
// etc.
template<typename Argument, int n>
struct SquareGenerator {
  using Type = Square<typename SquareGenerator<Argument, n - 1>::Type>;
  static Type Evaluate(Argument const& argument);
};
template<typename Argument>
struct SquareGenerator<Argument, 0> {
  using Type = Square<Argument>;
  static Type Evaluate(Argument const& argument);
};

template<typename Argument, typename>
struct SquaresGenerator;
template<typename Argument, int... orders>
struct SquaresGenerator<Argument, std::integer_sequence<int, orders...>> {
  using Type = std::tuple<typename SquareGenerator<Argument, orders>::Type...>;
  static Type Evaluate(Argument const& argument);
};

template<typename Argument, int n>
auto SquareGenerator<Argument, n>::Evaluate(Argument const& argument) -> Type {
  auto const argument_n_minus_1 =
      SquareGenerator<Argument, n - 1>::Evaluate(argument);
  return argument_n_minus_1 * argument_n_minus_1;
}

template<typename Argument>
auto SquareGenerator<Argument, 0>::Evaluate(Argument const& argument) -> Type {
  return argument * argument;
}

template<typename Argument, int... orders>
auto SquaresGenerator<Argument, std::integer_sequence<int, orders...>>::
    Evaluate(Argument const& argument) -> Type {
  return std::make_tuple(
      SquareGenerator<Argument, orders>::Evaluate(argument)...);
}

// Internal helper for Estrin evaluation.  |degree| is the degree of the overall
// polynomial, |low| and |subdegree| defines the subpolynomial that we currently
// evaluate, i.e., the one with a constant term coefficient
// |std::get<low>(coefficients)| and degree |subdegree|.
template<typename Value, typename Argument, int degree, int low, int subdegree>
struct InternalEstrinEvaluator {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low>
struct InternalEstrinEvaluator<Value, Argument, degree, low, 1> {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low>
struct InternalEstrinEvaluator<Value, Argument, degree, low, 0> {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low, int subdegree>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, subdegree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  static_assert(subdegree >= 2,
                "Unexpected subdegree in InternalEstrinEvaluator::Evaluate");
  // |n| is used to select |argument^(2^(n + 1))| = |argument^m|.
  constexpr int n = CeilingLog2(subdegree) - 1;
  // |m| is |2^(n + 1)|.
  constexpr int m = FloorOfPowerOf2(subdegree);
  return InternalEstrinEvaluator<Value, Argument, degree,
                                 low, m - 1>::
             Evaluate(coefficients, argument, argument_squares) +
         std::get<n>(argument_squares) *
             InternalEstrinEvaluator<Value, Argument, degree,
                                     low + m, subdegree - m>::
                 Evaluate(coefficients, argument, argument_squares);
}

template<typename Value, typename Argument, int degree, int low, int subdegree>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, subdegree>::
EvaluateDerivative(Coefficients const& coefficients,
                   Argument const& argument,
                   ArgumentSquares const& argument_squares) {
  static_assert(subdegree >= 2,
                "Unexpected subdegree in InternalEstrinEvaluator::"
                "EvaluateDerivative");
  // |n| is used to select |argument^(2^(n + 1))| = |argument^m|.
  constexpr int n = CeilingLog2(subdegree) - 1;
  // |m| is |2^(n + 1)|.
  constexpr int m = FloorOfPowerOf2(subdegree);
  return InternalEstrinEvaluator<Value, Argument, degree,
                                 low, m - 1>::
             EvaluateDerivative(coefficients, argument, argument_squares) +
         std::get<n>(argument_squares) *
             InternalEstrinEvaluator<Value, Argument, degree,
                                     low + m, subdegree - m>::
                 EvaluateDerivative(coefficients, argument, argument_squares);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 1>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return std::get<low>(coefficients) +
         argument * std::get<low + 1>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 0>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return std::get<low>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 1>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return low * std::get<low>(coefficients) +
         argument * (low + 1) * std::get<low + 1>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 0>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return low * std::get<low>(coefficients);
}

template<typename Value, typename Argument, int degree>
Value EstrinEvaluator<Value, Argument, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  using InternalEvaluator = InternalEstrinEvaluator<Value,
                                                    Argument,
                                                    degree,
                                                    /*low=*/0,
                                                    /*subdegree=*/degree>;
  return InternalEvaluator::Evaluate(
      coefficients,
      argument,
      InternalEvaluator::ArgumentSquaresGenerator::Evaluate(argument));
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
EstrinEvaluator<Value, Argument, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  using InternalEvaluator = InternalEstrinEvaluator<Value,
                                                    Argument,
                                                    degree,
                                                    /*low=*/1,
                                                    /*subdegree=*/degree - 1>;
  return InternalEvaluator::EvaluateDerivative(
      coefficients,
      argument,
      InternalEvaluator::ArgumentSquaresGenerator::Evaluate(argument));
}

// Internal helper for Horner evaluation.  |degree| is the degree of the overall
// polynomial, |low| defines the subpolynomial that we currently evaluate, i.e.,
// the one with a constant term coefficient |std::get<low>(coefficients)|.
template<typename Value, typename Argument, int degree, int low>
struct InternalHornerEvaluator {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         HornerEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  FORCE_INLINE(static) Derivative<Value, Argument, low>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree>
struct InternalHornerEvaluator<Value, Argument, degree, degree> {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         HornerEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, degree>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  FORCE_INLINE(static) Derivative<Value, Argument, degree>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalHornerEvaluator<Value, Argument, degree, low>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<low>(coefficients) +
         argument *
         InternalHornerEvaluator<Value, Argument, degree, low + 1>::
             Evaluate(coefficients, argument);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalHornerEvaluator<Value, Argument, degree, low>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<low>(coefficients) * low +
         argument *
         InternalHornerEvaluator<Value, Argument, degree, low + 1>::
             EvaluateDerivative(coefficients, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument, degree>
InternalHornerEvaluator<Value, Argument, degree, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument, degree>
InternalHornerEvaluator<Value, Argument, degree, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients) * degree;
}

template<typename Value, typename Argument, int degree>
Value HornerEvaluator<Value, Argument, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return InternalHornerEvaluator<Value, Argument, degree, /*low=*/0>::Evaluate(
      coefficients, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
HornerEvaluator<Value, Argument, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  // TODO(phl): Starting at 1 prevents us from having polynomials of degree 0.
  return InternalHornerEvaluator<Value, Argument, degree, /*low=*/1>::
      EvaluateDerivative(coefficients, argument);
}

}  // namespace internal_polynomial_evaluators
}  // namespace numerics
}  // namespace principia
<commit_msg>Derivation for constant polynomials.<commit_after>#pragma once

#include "numerics/polynomial_evaluators.hpp"

#include <tuple>

namespace principia {
namespace numerics {
namespace internal_polynomial_evaluators {

namespace {

// Greatest power of 2 less than or equal to n.  8 -> 8, 7 -> 4.
constexpr int FloorOfPowerOf2(int const n) {
  return n == 0 ? 0 : n == 1 ? 1 : FloorOfPowerOf2(n >> 1) << 1;
}

// Ceiling log2 of n.  8 -> 3, 7 -> 2.
constexpr int CeilingLog2(int const n) {
  return n == 1 ? 0 : CeilingLog2(n >> 1) + 1;
}

}  // namespace

// Generator for repeated squaring:
//   SquareGenerator<Length, 0>::Type is Exponentiation<Length, 2>
//   SquareGenerator<Length, 1>::Type is Exponentiation<Length, 4>
//   SquareGenerator<Length, n>::Type is Exponentiation<Length, 2^(n + 1)>
// etc.
template<typename Argument, int n>
struct SquareGenerator {
  using Type = Square<typename SquareGenerator<Argument, n - 1>::Type>;
  static Type Evaluate(Argument const& argument);
};
template<typename Argument>
struct SquareGenerator<Argument, 0> {
  using Type = Square<Argument>;
  static Type Evaluate(Argument const& argument);
};

template<typename Argument, typename>
struct SquaresGenerator;
template<typename Argument, int... orders>
struct SquaresGenerator<Argument, std::integer_sequence<int, orders...>> {
  using Type = std::tuple<typename SquareGenerator<Argument, orders>::Type...>;
  static Type Evaluate(Argument const& argument);
};

template<typename Argument, int n>
auto SquareGenerator<Argument, n>::Evaluate(Argument const& argument) -> Type {
  auto const argument_n_minus_1 =
      SquareGenerator<Argument, n - 1>::Evaluate(argument);
  return argument_n_minus_1 * argument_n_minus_1;
}

template<typename Argument>
auto SquareGenerator<Argument, 0>::Evaluate(Argument const& argument) -> Type {
  return argument * argument;
}

template<typename Argument, int... orders>
auto SquaresGenerator<Argument, std::integer_sequence<int, orders...>>::
    Evaluate(Argument const& argument) -> Type {
  return std::make_tuple(
      SquareGenerator<Argument, orders>::Evaluate(argument)...);
}

// Internal helper for Estrin evaluation.  |degree| is the degree of the overall
// polynomial, |low| and |subdegree| defines the subpolynomial that we currently
// evaluate, i.e., the one with a constant term coefficient
// |std::get<low>(coefficients)| and degree |subdegree|.
template<typename Value, typename Argument, int degree, int low, int subdegree>
struct InternalEstrinEvaluator {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low>
struct InternalEstrinEvaluator<Value, Argument, degree, low, 1> {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low>
struct InternalEstrinEvaluator<Value, Argument, degree, low, 0> {
  using ArgumentSquaresGenerator =
      SquaresGenerator<Argument,
                       std::make_integer_sequence<int, CeilingLog2(degree)>>;
  using ArgumentSquares = typename ArgumentSquaresGenerator::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         EstrinEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low> Evaluate(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
  FORCE_INLINE(static) Derivative<Value, Argument, low> EvaluateDerivative(
      Coefficients const& coefficients,
      Argument const& argument,
      ArgumentSquares const& argument_squares);
};

template<typename Value, typename Argument, int degree, int low, int subdegree>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, subdegree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  static_assert(subdegree >= 2,
                "Unexpected subdegree in InternalEstrinEvaluator::Evaluate");
  // |n| is used to select |argument^(2^(n + 1))| = |argument^m|.
  constexpr int n = CeilingLog2(subdegree) - 1;
  // |m| is |2^(n + 1)|.
  constexpr int m = FloorOfPowerOf2(subdegree);
  return InternalEstrinEvaluator<Value, Argument, degree,
                                 low, m - 1>::
             Evaluate(coefficients, argument, argument_squares) +
         std::get<n>(argument_squares) *
             InternalEstrinEvaluator<Value, Argument, degree,
                                     low + m, subdegree - m>::
                 Evaluate(coefficients, argument, argument_squares);
}

template<typename Value, typename Argument, int degree, int low, int subdegree>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, subdegree>::
EvaluateDerivative(Coefficients const& coefficients,
                   Argument const& argument,
                   ArgumentSquares const& argument_squares) {
  static_assert(subdegree >= 2,
                "Unexpected subdegree in InternalEstrinEvaluator::"
                "EvaluateDerivative");
  // |n| is used to select |argument^(2^(n + 1))| = |argument^m|.
  constexpr int n = CeilingLog2(subdegree) - 1;
  // |m| is |2^(n + 1)|.
  constexpr int m = FloorOfPowerOf2(subdegree);
  return InternalEstrinEvaluator<Value, Argument, degree,
                                 low, m - 1>::
             EvaluateDerivative(coefficients, argument, argument_squares) +
         std::get<n>(argument_squares) *
             InternalEstrinEvaluator<Value, Argument, degree,
                                     low + m, subdegree - m>::
                 EvaluateDerivative(coefficients, argument, argument_squares);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 1>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return std::get<low>(coefficients) +
         argument * std::get<low + 1>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 0>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return std::get<low>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 1>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return low * std::get<low>(coefficients) +
         argument * (low + 1) * std::get<low + 1>(coefficients);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalEstrinEvaluator<Value, Argument, degree, low, 0>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares const& argument_squares) {
  return low * std::get<low>(coefficients);
}

template<typename Value, typename Argument, int degree>
Value EstrinEvaluator<Value, Argument, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  using InternalEvaluator = InternalEstrinEvaluator<Value,
                                                    Argument,
                                                    degree,
                                                    /*low=*/0,
                                                    /*subdegree=*/degree>;
  return InternalEvaluator::Evaluate(
      coefficients,
      argument,
      InternalEvaluator::ArgumentSquaresGenerator::Evaluate(argument));
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
EstrinEvaluator<Value, Argument, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  using InternalEvaluator = InternalEstrinEvaluator<Value,
                                                    Argument,
                                                    degree,
                                                    /*low=*/1,
                                                    /*subdegree=*/degree - 1>;
  return InternalEvaluator::EvaluateDerivative(
      coefficients,
      argument,
      InternalEvaluator::ArgumentSquaresGenerator::Evaluate(argument));
}

// Internal helper for Horner evaluation.  |degree| is the degree of the overall
// polynomial, |low| defines the subpolynomial that we currently evaluate, i.e.,
// the one with a constant term coefficient |std::get<low>(coefficients)|.
template<typename Value, typename Argument, int degree, int low>
struct InternalHornerEvaluator {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         HornerEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, low>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  FORCE_INLINE(static) Derivative<Value, Argument, low>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree>
struct InternalHornerEvaluator<Value, Argument, degree, degree> {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree,
                                         HornerEvaluator>::Coefficients;

  FORCE_INLINE(static) Derivative<Value, Argument, degree>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  FORCE_INLINE(static) Derivative<Value, Argument, degree>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalHornerEvaluator<Value, Argument, degree, low>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<low>(coefficients) +
         argument *
         InternalHornerEvaluator<Value, Argument, degree, low + 1>::
             Evaluate(coefficients, argument);
}

template<typename Value, typename Argument, int degree, int low>
Derivative<Value, Argument, low>
InternalHornerEvaluator<Value, Argument, degree, low>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<low>(coefficients) * low +
         argument *
         InternalHornerEvaluator<Value, Argument, degree, low + 1>::
             EvaluateDerivative(coefficients, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument, degree>
InternalHornerEvaluator<Value, Argument, degree, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument, degree>
InternalHornerEvaluator<Value, Argument, degree, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients) * degree;
}

template<typename Value, typename Argument, int degree>
Value HornerEvaluator<Value, Argument, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return InternalHornerEvaluator<Value, Argument, degree, /*low=*/0>::Evaluate(
      coefficients, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
HornerEvaluator<Value, Argument, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  if constexpr (degree == 0) {
    return Derivative<Value, Argument>{};
  } else {
    return InternalHornerEvaluator<Value, Argument, degree, /*low=*/1>::
        EvaluateDerivative(coefficients, argument);
  }
}

}  // namespace internal_polynomial_evaluators
}  // namespace numerics
}  // namespace principia
<|endoftext|>