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

/*
 * Signal
 * Registers observers.
 * Notifies registered observers.
 */

#ifndef SKUI_CORE_SIGNAL_H
#define SKUI_CORE_SIGNAL_H

#include "core/slot.h++"
#include "core/trackable.h++"
#include "core/value_ptr.h++"

#include <algorithm>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <mutex>
#include <utility>

namespace skui::core
{
  namespace implementation
  {
    template<typename... ArgTypes>
    class signal_base : public tracker
                      , public trackable
    {
      using mutex_type = std::mutex;
      using mutex_lock = const std::lock_guard<mutex_type>;

    public:
      using function_type = void(*)(ArgTypes...);
      using slot_type = slot<void, ArgTypes...>;
      using object_slot_type = std::pair<const trackable*, value_ptr<slot_type>>;
      using connection_type = typename std::list<object_slot_type>::const_iterator;

      signal_base() = default;
      ~signal_base() override { disconnect_all(); }

      signal_base(const signal_base& other)
        : trackable{other}
        , slots{other.slots.begin(), other.slots.end()}
      {}

      signal_base(signal_base&& other) noexcept : slots(std::move(other.slots)) {}
      signal_base& operator=(signal_base other) { swap(slots, other.slots); return *this; }

      void trackable_deleted(const trackable* tracker) override
      {
        disconnect(tracker);
      }

      void trackable_moved(const trackable* old_object, const trackable* new_object) override
      {
        mutex_lock lock(slots_mutex);
        for(auto& object_slot : slots)
        {
          if(object_slot.first == old_object)
            object_slot.first = new_object;
        }
      }

      void trackable_copied(const trackable* old_object, const trackable* new_object) override
      {
        mutex_lock lock(slots_mutex);
        for(const auto& object_slot : slots)
        {
          if(object_slot.first == old_object)
            slots.emplace_back(new_object, object_slot.second);
        }
      }

      template<typename Callable, typename ReturnType = void>
      connection_type connect(Callable&& callable)
      {
        mutex_lock lock(slots_mutex);
        slots.emplace_back(nullptr, make_value<callable_slot<Callable, ReturnType, ArgTypes...>>(callable));
        return --slots.end();
      }

      template<typename Class, class FunctionClass, typename ReturnType, typename... FunctionArgTypes>
      connection_type connect(Class* object, ReturnType(FunctionClass::* slot)(FunctionArgTypes...))
      {
        static_assert(std::is_base_of<trackable, Class>::value,
                      "You can only connect to member functions of a trackable subclass.");
        static_assert(std::is_base_of<FunctionClass, Class>::value,
                      "You can only connect to member functions of a related object.");

        mutex_lock lock(slots_mutex);

        slots.emplace_back(object, make_value<member_function_slot<Class, ReturnType(FunctionClass::*)(FunctionArgTypes...), ReturnType, ArgTypes...>>(slot));
        object->track(this);

        return --slots.end();
      }

      template<typename Class, typename FunctionClass, typename ReturnType, typename... FunctionArgTypes>
      connection_type connect(const Class* object, ReturnType(FunctionClass::* slot)(FunctionArgTypes...) const)
      {
        static_assert(std::is_base_of<trackable, Class>::value,
                      "You can only connect to member functions of a trackable subclass");
        static_assert(std::is_base_of<FunctionClass, Class>::value,
                      "You can only connect to member functions of a related object.");

        mutex_lock lock(slots_mutex);

        slots.emplace_back(object, make_value<const_member_function_slot<Class, ReturnType(FunctionClass::*)(FunctionArgTypes...) const, ReturnType, ArgTypes...>>(slot));
        object->track(this);

        return --slots.end();
      }

      template<typename Signal>
      connection_type relay(const Signal& signal)
      {
        mutex_lock lock(slots_mutex);
        slots.emplace_back(&signal, make_value<const_member_function_slot<Signal, void(Signal::*)(ArgTypes...) const, void, ArgTypes...>>(&Signal::template emit<ArgTypes...>));
        signal.track(this);
        return --slots.end();
      }

      // removes a previously made connection, handles lifetime tracking if it was the last connection to a specific object
      void disconnect(connection_type connection)
      {
        mutex_lock lock(slots_mutex);
        const trackable* object = connection->first;

        slots.erase(connection);
        if(object && std::any_of(slots.begin(), slots.end(),
                                 [&object](const object_slot_type& object_slot)
        { return object_slot.first == object; }))
          object->untrack(this);
      }

      // removes all connections to an object
      void disconnect(const trackable* object)
      {
        mutex_lock lock(slots_mutex);
        object->untrack(this);
        slots.remove_if([object](const object_slot_type& object_slot)
        { return object == object_slot.first; });
      }

      // removes all connections
      void disconnect_all()
      {
        mutex_lock lock(slots_mutex);
        for(object_slot_type& object_slot : slots)
        {
          auto trackable = object_slot.first;
          if(trackable)
            trackable->untrack(this);
        }
        slots.clear();
      }

    protected:
      // mutable here allows to connect to a const object's signals
      mutable std::list<object_slot_type> slots;
      mutable mutex_type slots_mutex;
    };
  }

  template<typename... ArgTypes>
  class signal : public implementation::signal_base<ArgTypes...>
  {
  public:
    signal() = default;

    template<typename... EmitArgTypes>
    void emit(EmitArgTypes&&... arguments) const
    {
      std::lock_guard<decltype(this->slots_mutex)> lock(this->slots_mutex);
      for(auto&& object_slot : this->slots)
      {
        // This needs a dynamic_cast<const void*> e.g. when trackable is not the first parent class
        object_slot.second->operator()(dynamic_cast<const void*>(object_slot.first),
                                       std::forward<EmitArgTypes>(arguments)...);
      }
    }

    template<typename... EmitArgTypes>
    void operator()(EmitArgTypes&&... arguments) const
    {
      emit(std::forward<EmitArgTypes>(arguments)...);
    }
  };
}

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

/*
 * Signal
 * Registers observers.
 * Notifies registered observers.
 */

#ifndef SKUI_CORE_SIGNAL_H
#define SKUI_CORE_SIGNAL_H

#include "core/slot.h++"
#include "core/trackable.h++"
#include "core/value_ptr.h++"

#include <algorithm>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <mutex>
#include <utility>

namespace skui::core
{
  namespace implementation
  {
    template<typename... ArgTypes>
    class signal_base : public tracker
                      , public trackable
    {
    public:
      using function_type = void(*)(ArgTypes...);
      using slot_type = slot<void, ArgTypes...>;
      using object_slot_type = std::pair<const trackable*, value_ptr<slot_type>>;
      using connection_type = typename std::list<object_slot_type>::const_iterator;

      signal_base() = default;
      ~signal_base() override { disconnect_all(); }

      signal_base(const signal_base& other)
        : trackable{other}
        , slots{other.slots.begin(), other.slots.end()}
      {}

      signal_base(signal_base&& other) noexcept : slots(std::move(other.slots)) {}
      signal_base& operator=(signal_base other) { swap(slots, other.slots); return *this; }

      void trackable_deleted(const trackable* tracker) override
      {
        disconnect(tracker);
      }

      void trackable_moved(const trackable* old_object, const trackable* new_object) override
      {
        std::lock_guard lock{slots_mutex};
        for(auto& object_slot : slots)
        {
          if(object_slot.first == old_object)
            object_slot.first = new_object;
        }
      }

      void trackable_copied(const trackable* old_object, const trackable* new_object) override
      {
        std::lock_guard lock{slots_mutex};
        for(const auto& object_slot : slots)
        {
          if(object_slot.first == old_object)
            slots.emplace_back(new_object, object_slot.second);
        }
      }

      template<typename Callable, typename ReturnType = void>
      connection_type connect(Callable&& callable)
      {
        std::lock_guard lock{slots_mutex};
        slots.emplace_back(nullptr, make_value<callable_slot<Callable, ReturnType, ArgTypes...>>(callable));
        return --slots.end();
      }

      template<typename Class, class FunctionClass, typename ReturnType, typename... FunctionArgTypes>
      connection_type connect(Class* object, ReturnType(FunctionClass::* slot)(FunctionArgTypes...))
      {
        static_assert(std::is_base_of<trackable, Class>::value,
                      "You can only connect to member functions of a trackable subclass.");
        static_assert(std::is_base_of<FunctionClass, Class>::value,
                      "You can only connect to member functions of a related object.");

        std::lock_guard lock{slots_mutex};

        slots.emplace_back(object, make_value<member_function_slot<Class, ReturnType(FunctionClass::*)(FunctionArgTypes...), ReturnType, ArgTypes...>>(slot));
        object->track(this);

        return --slots.end();
      }

      template<typename Class, typename FunctionClass, typename ReturnType, typename... FunctionArgTypes>
      connection_type connect(const Class* object, ReturnType(FunctionClass::* slot)(FunctionArgTypes...) const)
      {
        static_assert(std::is_base_of<trackable, Class>::value,
                      "You can only connect to member functions of a trackable subclass");
        static_assert(std::is_base_of<FunctionClass, Class>::value,
                      "You can only connect to member functions of a related object.");

        std::lock_guard lock{slots_mutex};

        slots.emplace_back(object, make_value<const_member_function_slot<Class, ReturnType(FunctionClass::*)(FunctionArgTypes...) const, ReturnType, ArgTypes...>>(slot));
        object->track(this);

        return --slots.end();
      }

      template<typename Signal>
      connection_type relay(const Signal& signal)
      {
        std::lock_guard lock{slots_mutex};
        slots.emplace_back(&signal, make_value<const_member_function_slot<Signal, void(Signal::*)(ArgTypes...) const, void, ArgTypes...>>(&Signal::template emit<ArgTypes...>));
        signal.track(this);
        return --slots.end();
      }

      // removes a previously made connection, handles lifetime tracking if it was the last connection to a specific object
      void disconnect(connection_type connection)
      {
        std::lock_guard lock{slots_mutex};
        const trackable* object = connection->first;

        slots.erase(connection);
        if(object && std::any_of(slots.begin(), slots.end(),
                                 [&object](const object_slot_type& object_slot)
        { return object_slot.first == object; }))
          object->untrack(this);
      }

      // removes all connections to an object
      void disconnect(const trackable* object)
      {
        std::lock_guard lock{slots_mutex};
        object->untrack(this);
        slots.remove_if([object](const object_slot_type& object_slot)
        { return object == object_slot.first; });
      }

      // removes all connections
      void disconnect_all()
      {
        std::lock_guard lock{slots_mutex};
        for(object_slot_type& object_slot : slots)
        {
          auto trackable = object_slot.first;
          if(trackable)
            trackable->untrack(this);
        }
        slots.clear();
      }

    protected:
      // mutable here allows to connect to a const object's signals
      mutable std::list<object_slot_type> slots;
      mutable std::mutex slots_mutex;
    };
  }

  template<typename... ArgTypes>
  class signal : public implementation::signal_base<ArgTypes...>
  {
  public:
    signal() = default;

    template<typename... EmitArgTypes>
    void emit(EmitArgTypes&&... arguments) const
    {
      std::lock_guard lock{this->slots_mutex};

      for(auto&& object_slot : this->slots)
      {
        // This needs a dynamic_cast<const void*> e.g. when trackable is not the first parent class
        object_slot.second->operator()(dynamic_cast<const void*>(object_slot.first),
                                       std::forward<EmitArgTypes>(arguments)...);
      }
    }

    template<typename... EmitArgTypes>
    void operator()(EmitArgTypes&&... arguments) const
    {
      emit(std::forward<EmitArgTypes>(arguments)...);
    }
  };
}

#endif
<|endoftext|>


<commit_before>/*
 * SSL/TLS configuration.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_domain.hxx"
#include "SniCallback.hxx"
#include "Error.hxx"
#include "Basic.hxx"
#include "Unique.hxx"
#include "Name.hxx"
#include "Util.hxx"
#include "util/AllocatedString.hxx"
#include "util/StringView.hxx"

#include <inline/compiler.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <algorithm>

#include <assert.h>

struct SslFactoryCertKey {
    UniqueSSL_CTX ssl_ctx;

    AllocatedString<> common_name = nullptr;
    size_t cn_length;

    SslFactoryCertKey() = default;

    SslFactoryCertKey(SslFactoryCertKey &&other) = default;
    SslFactoryCertKey &operator=(SslFactoryCertKey &&other) = default;

    void LoadServer(const SslConfig &parent_config,
                    const SslCertKeyConfig &config);

    void CacheCommonName(X509_NAME *subject) {
        common_name = NidToString(*subject, NID_commonName);
        if (common_name != nullptr)
            cn_length = strlen(common_name.c_str());
    }

    void CacheCommonName(X509 *cert) {
        assert(common_name == nullptr);

        X509_NAME *subject = X509_get_subject_name(cert);
        if (subject != nullptr)
            CacheCommonName(subject);
    }

    gcc_pure
    bool MatchCommonName(StringView host_name) const;

    UniqueSSL Make() const {
        UniqueSSL ssl(SSL_new(ssl_ctx.get()));
        if (!ssl)
            throw SslError("SSL_new() failed");

        return ssl;
    }

    void Apply(SSL *ssl) const {
        SSL_set_SSL_CTX(ssl, ssl_ctx.get());
    }

    unsigned Flush(long tm);
};

struct SslFactory {
    std::vector<SslFactoryCertKey> cert_key;

    const std::unique_ptr<SslSniCallback> sni;

    SslFactory(std::unique_ptr<SslSniCallback> &&_sni)
        :sni(std::move(_sni)) {}

    gcc_pure
    const SslFactoryCertKey *FindCommonName(StringView host_name) const;

    void EnableSNI();

    UniqueSSL Make();

    unsigned Flush(long tm);
};

static void
load_certs_keys(SslFactory &factory, const SslConfig &config)
{
    factory.cert_key.reserve(config.cert_key.size());

    for (const auto &c : config.cert_key) {
        SslFactoryCertKey ck;
        ck.LoadServer(config, c);

        factory.cert_key.emplace_back(std::move(ck));
    }
}

static void
ApplyServerConfig(SSL_CTX *ssl_ctx, const SslCertKeyConfig &cert_key)
{
    ERR_clear_error();

    if (SSL_CTX_use_RSAPrivateKey_file(ssl_ctx,
                                       cert_key.key_file.c_str(),
                                       SSL_FILETYPE_PEM) != 1)
        throw SslError("Failed to load key file " +
                       cert_key.key_file);

    if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
                                           cert_key.cert_file.c_str()) != 1)
        throw SslError("Failed to load certificate file " +
                       cert_key.cert_file);
}

inline bool
SslFactoryCertKey::MatchCommonName(StringView host_name) const
{
    if (common_name == nullptr)
        return false;

    if (cn_length == host_name.size &&
        memcmp(host_name.data, common_name.c_str(), host_name.size) == 0)
        return true;

    if (common_name[0] == '*' && common_name[1] == '.' &&
        common_name[2] != 0) {
        if (host_name.size >= cn_length &&
            /* match only one segment (no dots) */
            memchr(host_name.data, '.',
                   host_name.size - cn_length + 1) == nullptr &&
            memcmp(host_name.data + host_name.size - cn_length + 1,
                   common_name.c_str() + 1, cn_length - 1) == 0)
            return true;
    }

    return false;
}

inline const SslFactoryCertKey *
SslFactory::FindCommonName(StringView host_name) const
{
    for (const auto &ck : cert_key)
        if (ck.MatchCommonName(host_name))
            return &ck;

    return nullptr;
}

static void
PrintException(const std::exception &e)
{
    fprintf(stderr, "%s\n", e.what());
    try {
        std::rethrow_if_nested(e);
    } catch (const std::exception &nested) {
        PrintException(nested);
    } catch (...) {
        fprintf(stderr, "Unrecognized nested exception\n");
    }
}

static int
ssl_servername_callback(SSL *ssl, gcc_unused int *al,
                        const SslFactory &factory)
{
    const char *_host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
    if (_host_name == nullptr)
        return SSL_TLSEXT_ERR_OK;

    const StringView host_name(_host_name);

    /* find the first certificate that matches */

    const auto *ck = factory.FindCommonName(host_name);
    if (ck != nullptr) {
        /* found it - now use it */
        ck->Apply(ssl);
    } else if (factory.sni) {
        try {
            factory.sni->OnSni(ssl, host_name.data);
        } catch (const std::exception &e) {
            PrintException(e);
        }
    }

    return SSL_TLSEXT_ERR_OK;
}

inline void
SslFactory::EnableSNI()
{
    SSL_CTX *ssl_ctx = cert_key.front().ssl_ctx.get();

    if (!SSL_CTX_set_tlsext_servername_callback(ssl_ctx,
                                                ssl_servername_callback) ||
        !SSL_CTX_set_tlsext_servername_arg(ssl_ctx, this))
        throw SslError("SSL_CTX_set_tlsext_servername_callback() failed");
}

inline UniqueSSL
SslFactory::Make()
{
    auto ssl = cert_key.front().Make();

    SSL_set_accept_state(ssl.get());

    return ssl;
}

inline unsigned
SslFactoryCertKey::Flush(long tm)
{
    unsigned before = SSL_CTX_sess_number(ssl_ctx.get());
    SSL_CTX_flush_sessions(ssl_ctx.get(), tm);
    unsigned after = SSL_CTX_sess_number(ssl_ctx.get());
    return after < before ? before - after : 0;
}

inline unsigned
SslFactory::Flush(long tm)
{
    unsigned n = 0;
    for (auto &i : cert_key)
        n += i.Flush(tm);
    return n;
}

void
SslFactoryCertKey::LoadServer(const SslConfig &parent_config,
                              const SslCertKeyConfig &config)
{
    assert(ssl_ctx == nullptr);

    ssl_ctx = CreateBasicSslCtx(true);

    assert(!parent_config.cert_key.empty());

    ApplyServerConfig(ssl_ctx.get(), config);
    ApplyServerConfig(ssl_ctx.get(), parent_config);

    auto ssl = Make();

    X509 *cert = SSL_get_certificate(ssl.get());
    if (cert == nullptr)
        throw SslError("No certificate in SSL_CTX");

    EVP_PKEY *key = SSL_get_privatekey(ssl.get());
    if (key == nullptr)
        throw SslError("No certificate in SSL_CTX");

    if (!MatchModulus(*cert, *key))
        throw SslError("Key '" + config.key_file +
                       "' does not match certificate '" +
                       config.cert_file + "'");

    CacheCommonName(cert);
}

SslFactory *
ssl_factory_new_server(const SslConfig &config,
                       std::unique_ptr<SslSniCallback> &&sni)
{
    assert(!config.cert_key.empty());

    std::unique_ptr<SslFactory> factory(new SslFactory(std::move(sni)));

    assert(!config.cert_key.empty());

    load_certs_keys(*factory, config);

    if (factory->cert_key.size() > 1 || factory->sni)
        factory->EnableSNI();

    return factory.release();
}

void
ssl_factory_free(SslFactory *factory)
{
    delete factory;
}

UniqueSSL
ssl_factory_make(SslFactory &factory)
{
    return factory.Make();
}

unsigned
ssl_factory_flush(SslFactory &factory, long tm)
{
    return factory.Flush(tm);
}
<commit_msg>ssl/factory: move code to struct Name<commit_after>/*
 * SSL/TLS configuration.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "ssl_factory.hxx"
#include "ssl_config.hxx"
#include "ssl_domain.hxx"
#include "SniCallback.hxx"
#include "Error.hxx"
#include "Basic.hxx"
#include "Unique.hxx"
#include "Name.hxx"
#include "Util.hxx"
#include "util/AllocatedString.hxx"
#include "util/StringView.hxx"

#include <inline/compiler.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include <algorithm>

#include <assert.h>

struct SslFactoryCertKey {
    struct Name {
        AllocatedString<> value;
        size_t length;

        Name(std::nullptr_t _value):value(_value) {}

        Name(AllocatedString<> &&_value)
            :value(std::move(_value)), length(strlen(value.c_str())) {}

        gcc_pure
        bool Match(StringView host_name) const;
    };

    UniqueSSL_CTX ssl_ctx;

    Name name = nullptr;

    SslFactoryCertKey() = default;

    SslFactoryCertKey(SslFactoryCertKey &&other) = default;
    SslFactoryCertKey &operator=(SslFactoryCertKey &&other) = default;

    void LoadServer(const SslConfig &parent_config,
                    const SslCertKeyConfig &config);

    void CacheCommonName(X509_NAME *subject) {
        auto common_name = NidToString(*subject, NID_commonName);
        if (common_name != nullptr)
            name = Name(std::move(common_name));
    }

    void CacheCommonName(X509 *cert) {
        X509_NAME *subject = X509_get_subject_name(cert);
        if (subject != nullptr)
            CacheCommonName(subject);
    }

    gcc_pure
    bool MatchCommonName(StringView host_name) const;

    UniqueSSL Make() const {
        UniqueSSL ssl(SSL_new(ssl_ctx.get()));
        if (!ssl)
            throw SslError("SSL_new() failed");

        return ssl;
    }

    void Apply(SSL *ssl) const {
        SSL_set_SSL_CTX(ssl, ssl_ctx.get());
    }

    unsigned Flush(long tm);
};

struct SslFactory {
    std::vector<SslFactoryCertKey> cert_key;

    const std::unique_ptr<SslSniCallback> sni;

    SslFactory(std::unique_ptr<SslSniCallback> &&_sni)
        :sni(std::move(_sni)) {}

    gcc_pure
    const SslFactoryCertKey *FindCommonName(StringView host_name) const;

    void EnableSNI();

    UniqueSSL Make();

    unsigned Flush(long tm);
};

static void
load_certs_keys(SslFactory &factory, const SslConfig &config)
{
    factory.cert_key.reserve(config.cert_key.size());

    for (const auto &c : config.cert_key) {
        SslFactoryCertKey ck;
        ck.LoadServer(config, c);

        factory.cert_key.emplace_back(std::move(ck));
    }
}

static void
ApplyServerConfig(SSL_CTX *ssl_ctx, const SslCertKeyConfig &cert_key)
{
    ERR_clear_error();

    if (SSL_CTX_use_RSAPrivateKey_file(ssl_ctx,
                                       cert_key.key_file.c_str(),
                                       SSL_FILETYPE_PEM) != 1)
        throw SslError("Failed to load key file " +
                       cert_key.key_file);

    if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
                                           cert_key.cert_file.c_str()) != 1)
        throw SslError("Failed to load certificate file " +
                       cert_key.cert_file);
}

inline bool
SslFactoryCertKey::Name::Match(StringView host_name) const
{
    if (value == nullptr)
        return false;

    if (length == host_name.size &&
        memcmp(host_name.data, value.c_str(), host_name.size) == 0)
        return true;

    if (value[0] == '*' && value[1] == '.' && value[2] != 0) {
        if (host_name.size >= length &&
            /* match only one segment (no dots) */
            memchr(host_name.data, '.',
                   host_name.size - length + 1) == nullptr &&
            memcmp(host_name.data + host_name.size - length + 1,
                   value.c_str() + 1, length - 1) == 0)
            return true;
    }

    return false;
}

inline bool
SslFactoryCertKey::MatchCommonName(StringView host_name) const
{
    return name.Match(host_name);
}

inline const SslFactoryCertKey *
SslFactory::FindCommonName(StringView host_name) const
{
    for (const auto &ck : cert_key)
        if (ck.MatchCommonName(host_name))
            return &ck;

    return nullptr;
}

static void
PrintException(const std::exception &e)
{
    fprintf(stderr, "%s\n", e.what());
    try {
        std::rethrow_if_nested(e);
    } catch (const std::exception &nested) {
        PrintException(nested);
    } catch (...) {
        fprintf(stderr, "Unrecognized nested exception\n");
    }
}

static int
ssl_servername_callback(SSL *ssl, gcc_unused int *al,
                        const SslFactory &factory)
{
    const char *_host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
    if (_host_name == nullptr)
        return SSL_TLSEXT_ERR_OK;

    const StringView host_name(_host_name);

    /* find the first certificate that matches */

    const auto *ck = factory.FindCommonName(host_name);
    if (ck != nullptr) {
        /* found it - now use it */
        ck->Apply(ssl);
    } else if (factory.sni) {
        try {
            factory.sni->OnSni(ssl, host_name.data);
        } catch (const std::exception &e) {
            PrintException(e);
        }
    }

    return SSL_TLSEXT_ERR_OK;
}

inline void
SslFactory::EnableSNI()
{
    SSL_CTX *ssl_ctx = cert_key.front().ssl_ctx.get();

    if (!SSL_CTX_set_tlsext_servername_callback(ssl_ctx,
                                                ssl_servername_callback) ||
        !SSL_CTX_set_tlsext_servername_arg(ssl_ctx, this))
        throw SslError("SSL_CTX_set_tlsext_servername_callback() failed");
}

inline UniqueSSL
SslFactory::Make()
{
    auto ssl = cert_key.front().Make();

    SSL_set_accept_state(ssl.get());

    return ssl;
}

inline unsigned
SslFactoryCertKey::Flush(long tm)
{
    unsigned before = SSL_CTX_sess_number(ssl_ctx.get());
    SSL_CTX_flush_sessions(ssl_ctx.get(), tm);
    unsigned after = SSL_CTX_sess_number(ssl_ctx.get());
    return after < before ? before - after : 0;
}

inline unsigned
SslFactory::Flush(long tm)
{
    unsigned n = 0;
    for (auto &i : cert_key)
        n += i.Flush(tm);
    return n;
}

void
SslFactoryCertKey::LoadServer(const SslConfig &parent_config,
                              const SslCertKeyConfig &config)
{
    assert(ssl_ctx == nullptr);

    ssl_ctx = CreateBasicSslCtx(true);

    assert(!parent_config.cert_key.empty());

    ApplyServerConfig(ssl_ctx.get(), config);
    ApplyServerConfig(ssl_ctx.get(), parent_config);

    auto ssl = Make();

    X509 *cert = SSL_get_certificate(ssl.get());
    if (cert == nullptr)
        throw SslError("No certificate in SSL_CTX");

    EVP_PKEY *key = SSL_get_privatekey(ssl.get());
    if (key == nullptr)
        throw SslError("No certificate in SSL_CTX");

    if (!MatchModulus(*cert, *key))
        throw SslError("Key '" + config.key_file +
                       "' does not match certificate '" +
                       config.cert_file + "'");

    CacheCommonName(cert);
}

SslFactory *
ssl_factory_new_server(const SslConfig &config,
                       std::unique_ptr<SslSniCallback> &&sni)
{
    assert(!config.cert_key.empty());

    std::unique_ptr<SslFactory> factory(new SslFactory(std::move(sni)));

    assert(!config.cert_key.empty());

    load_certs_keys(*factory, config);

    if (factory->cert_key.size() > 1 || factory->sni)
        factory->EnableSNI();

    return factory.release();
}

void
ssl_factory_free(SslFactory *factory)
{
    delete factory;
}

UniqueSSL
ssl_factory_make(SslFactory &factory)
{
    return factory.Make();
}

unsigned
ssl_factory_flush(SslFactory &factory, long tm)
{
    return factory.Flush(tm);
}
<|endoftext|>


<commit_before>//#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif  // _DEBUG

#include <enet/enet.h>

#include "starlight_win32.h"
#include "starlight_graphics.h"
#include "starlight_game.h"
#include <imgui.h>
#include <atomic>
#include "starlight_thread_safe_queue.h"
#include "starlight_log.h"
#include "starlight_memory.h"

#ifdef SL_UB
  #ifdef _DEBUG
    #ifdef _WIN64
      static const wchar_t* s_dllName = L"starlight_x64_UB Debug.dll";
    #else
      static const wchar_t* s_dllName = L"starlight_Win32_UB Debug.dll";
    #endif
  #endif
#else
  #ifdef _DEBUG
    #ifdef _WIN64
      static const wchar_t* s_dllName = L"starlight_x64_Debug.dll";
    #else
      static const wchar_t* s_dllName = L"starlight_Win32_Debug.dll";
    #endif
  #endif
#endif

// Globals
static std::mutex s_mutex;
static graphics::API* g_renderApi;

static HWND s_hwnd = nullptr;
static util::ThreadSafeQueue<WindowEvent>* s_queue;
static std::atomic_bool s_running;

static LARGE_INTEGER s_lastTime;
static LARGE_INTEGER s_perfFreq;

static GameFuncs s_gameFuncs;

// This is ugly
#ifdef STARLIGHT_D3D11
static graphics::D3D11 d3d11;
#endif
#ifdef STARLIGHT_D3D10
static graphics::D3D10 d3d10;
#endif

CALCULATE_DELTA_TIME(CalculateDeltaTime) {
	LARGE_INTEGER currentTime;
	QueryPerformanceCounter(&currentTime);
	float deltaTime = float(currentTime.QuadPart - s_lastTime.QuadPart) / float(s_perfFreq.QuadPart);
	s_lastTime = currentTime;
	return deltaTime;
}

GameFuncs LoadGameFuncs() {
	GameFuncs gameFuncs;
	ZERO_MEM(&gameFuncs, sizeof(GameFuncs));

#if _DEBUG
	HMODULE lib = LoadLibraryW(s_dllName);
	if (!lib) {
		GetLastError();
	}
	else {
		gameFuncs.DestroyGame = (DestroyGameFunc*) GetProcAddress(lib, "DestroyGame");
		gameFuncs.UpdateGame = (UpdateGameFunc*) GetProcAddress(lib, "UpdateGame");
		gameFuncs.InitLogger = (InitLoggerFunc*) GetProcAddress(lib, "InitLogger");
		gameFuncs.DestroyLogger = (DestroyLoggerFunc*) GetProcAddress(lib, "DestroyLogger");
		gameFuncs.LogInfo = (LogInfoFunc*) GetProcAddress(lib, "LogInfo");
		if (!(gameFuncs.DestroyGame
			&& gameFuncs.UpdateGame
			&& gameFuncs.InitLogger
			&& gameFuncs.DestroyLogger
			&& gameFuncs.LogInfo)) {
			GetLastError();
		}
	}
#else
	gameFuncs.DestroyGame = game::DestroyGame;
	gameFuncs.UpdateGame = game::UpdateGame;
	gameFuncs.InitLogger = logger::InitLogger;
	gameFuncs.DestroyLogger = logger::DestroyLogger;
	gameFuncs.LogInfo = logger::LogInfo;
#endif

	return gameFuncs;
}

// Try to initialize the specified rendering API.
// TODO: Remove globals for the APIs
// If it fails, it returns false.
bool LoadRenderApiImpl(EGraphicsApi e) {
	graphics::API* api = nullptr;
	switch (e) {
#ifdef STARLIGHT_D3D10
	case D3D10:
		logger::LogInfo("Loading D3D10...");
		api = &d3d10;
		break;
#endif
#ifdef STARLIGHT_D3D11
	case D3D11:
		s_gameFuncs.LogInfo("Loading D3D11...");
		api = &d3d11;
		break;
#endif
	default:
		s_gameFuncs.LogInfo("The requested graphics API is not enabled.");
		return false;
	}

	// Cannot init if there is no window
	assert(s_hwnd);

	PlatformData platformData;
	ZeroMemory(&platformData, sizeof(platformData));
	platformData.hWnd = s_hwnd;

#if 1
	// Init new -> destroy old
	if (api->Init(&platformData, &s_gameFuncs)) {
		if (g_renderApi) {
			g_renderApi->Destroy();
		}
		g_renderApi = api;

		// Reload fonts
		ImGuiIO& io = ImGui::GetIO();
		io.Fonts->Clear();
		io.Fonts->AddFontFromFileTTF("assets/DroidSans.ttf", 14.0f, nullptr, io.Fonts->GetGlyphRangesCyrillic());
		return true;
	}
#else
	// Destroy old -> init new
	if (g_renderApi) {
		g_renderApi->Destroy();
		g_renderApi = nullptr;
	}
	if (api->Init(&platformData)) {
		g_renderApi = api;
		return true;
	}

#endif
	return false;
}

#if 0
class HeapArea
{
public:
	explicit HeapArea(std::size_t bytes) {
		start = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	}

	~HeapArea() {
		VirtualFree(start, 0, MEM_RELEASE);
	}

	void* GetStart() { return start; }
	void* GetEnd() { return end; }

private:
	void* start;
	void* end;
};

static HeapArea* heapArea;

void* CALLBACK LibMalloc(std::size_t size) {
	return nullptr;
}

void CALLBACK LibFree(void* ptr) {

}
#endif

void ParseMessages() {
	WindowEvent message;
	// Clear queue for now
	// TODO: Process input
	while (s_queue->Dequeue(&message)) {}
}

void MyThreadFunction() {
	EGraphicsApi graphicsApi = EGraphicsApi::D3D11;
	if (!LoadRenderApiImpl(graphicsApi)) {
		s_running.store(false);
		return;
	}

	// Init time
	QueryPerformanceFrequency(&s_perfFreq);
	QueryPerformanceCounter(&s_lastTime);

	GameInfo gameInfo;
	ZeroMemory(&gameInfo, sizeof(gameInfo));
	gameInfo.graphicsApi = graphicsApi;
	gameInfo.imguiState = ImGui::GetInternalState();
	//heapArea = new HeapArea(512 * 1024 * 1024);
	//memory::SimpleArena arena(heapArea);
	//gameInfo.allocator = &arena;
	gameInfo.CalculateDeltaTime = CalculateDeltaTime;

	// ENet
#if 0
	ENetCallbacks callbacks;
	ZERO_MEM(&callbacks, sizeof(callbacks));
	callbacks.malloc = memory::malloc;
	callbacks.free = memory::free;
	callbacks.no_memory = memory::no_memory;

	if (enet_initialize_with_callbacks(ENET_VERSION, &callbacks) != 0)
#endif
	if (enet_initialize() != 0)
	{
		s_running.store(false);
		return;
	}

	// Main loop
	while (s_running.load())
	{
		// Check if graphics API change was requested
		if (gameInfo.graphicsApi != graphicsApi) {
			if (LoadRenderApiImpl(gameInfo.graphicsApi)) {
				graphicsApi = gameInfo.graphicsApi;
			} else {
				gameInfo.graphicsApi = graphicsApi;
			}
		}

		ParseMessages();

		g_renderApi->ImGuiNewFrame();

		s_gameFuncs.UpdateGame(&gameInfo, g_renderApi);

		// Rendering
		if (std::try_lock(s_mutex)) {
			g_renderApi->Render();
			s_mutex.unlock();
		}
	}

	s_gameFuncs.DestroyGame();
	g_renderApi->Destroy();
	ImGui::Shutdown();
	g_renderApi = nullptr;

	//delete heapArea;

	enet_deinitialize();
}

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	WindowEvent params;
	ZeroMemory(&params, sizeof(params));
	params.hWnd = hWnd;
	params.msg = msg;
	params.wParam = wParam;
	params.lParam = lParam;

	s_queue->Enqueue(params);

	if (g_renderApi && g_renderApi->ImGuiHandleEvent(&params))
		return true;

	switch (msg)
	{
	case WM_SIZE:
		if (g_renderApi && wParam != SIZE_MINIMIZED) {
			g_renderApi->Resize((int32_t) LOWORD(lParam), (int32_t) HIWORD(lParam));
			//return 0;
		}
		break;
	case WM_SYSCOMMAND:
		if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
			return 0;
		break;
	case WM_DESTROY:
		s_running.store(false);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProcW(hWnd, msg, wParam, lParam);
}

int CALLBACK WinMain(
	HINSTANCE   hInstance,
	HINSTANCE   hPrevInstance,
	LPSTR       lpCmdLine,
	int         nCmdShow)
{
	//std::set_new_handler(memory::no_memory);

	s_gameFuncs = LoadGameFuncs();

	ImGuiIO& io = ImGui::GetIO();
	//io.MemAllocFn = memory::malloc;
	//io.MemFreeFn = memory::free;

	//_crtBreakAlloc = 4015;
	s_queue = new util::ThreadSafeQueue<WindowEvent>();

	s_gameFuncs.InitLogger();

	s_gameFuncs.LogInfo(SL_BUILD_DATE);

	auto className = L"StarlightClassName";

	WNDCLASSEXW wndClass = { 0 };
	wndClass.cbSize = sizeof(WNDCLASSEXW);
	wndClass.style = CS_CLASSDC;
	wndClass.lpfnWndProc = WndProc;
	wndClass.hInstance = GetModuleHandleW(nullptr);
	wndClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
	wndClass.lpszClassName = className;

	RegisterClassExW(&wndClass);

	// Get desktop rectangle
	RECT desktopRect;
	GetClientRect(GetDesktopWindow(), &desktopRect);

	// Get window rectangle
	RECT windowRect = { 0, 0, 800, 600 }; // TODO: Config file?
	AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);

	// Calculate window dimensions
	auto windowWidth = windowRect.right - windowRect.left;
	auto windowHeight = windowRect.bottom - windowRect.top;

	s_hwnd = CreateWindowExW(
		0L,
		className,
		L"Starlight",
		WS_OVERLAPPEDWINDOW,
		desktopRect.right / 2 - windowWidth / 2,
		desktopRect.bottom / 2 - windowHeight / 2,
		windowWidth,
		windowHeight,
		nullptr,
		nullptr,
		GetModuleHandleW(nullptr),
		nullptr
		);

	// Show the window
	ShowWindow(s_hwnd, SW_SHOWDEFAULT);
	UpdateWindow(s_hwnd);

	// Create thread
	s_running.store(true);
	std::thread thread(MyThreadFunction);

	// Message loop
	MSG msg;
	while (s_running.load() && GetMessageW(&msg, nullptr, 0, 0))
	{
		std::lock_guard<std::mutex> lock(s_mutex);
		TranslateMessage(&msg);
		DispatchMessageW(&msg);
	}

	thread.join();

	s_gameFuncs.DestroyLogger();

	io.Fonts->Clear();

	delete s_queue;

	UnregisterClassW(className, GetModuleHandleW(nullptr));

	_CrtDumpMemoryLeaks();
}

#if 0

// Global memory functions

void* MEM_CALL operator new(std::size_t n) throw() {
	return memory::malloc(n);
}

void* MEM_CALL operator new[](std::size_t s) throw() {
	return operator new(s);
}

void MEM_CALL operator delete(void * p) throw() {
	return memory::free(p);
}

void MEM_CALL operator delete[](void *p) throw() {
	return operator delete(p);
}

// Wrappers

void* MEM_CALL memory::malloc(std::size_t size) {
	return ::malloc(size);
}

void MEM_CALL memory::free(void* ptr) {
	return ::free(ptr);
}

void* MEM_CALL memory::realloc(void* ptr, std::size_t size) {
	return ::realloc(ptr, size);
}

void MEM_CALL memory::no_memory() {

}
#endif
<commit_msg>Fix UB dll filename string<commit_after>//#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif  // _DEBUG

#include <enet/enet.h>

#include "starlight_win32.h"
#include "starlight_graphics.h"
#include "starlight_game.h"
#include <imgui.h>
#include <atomic>
#include "starlight_thread_safe_queue.h"
#include "starlight_log.h"
#include "starlight_memory.h"

#ifdef SL_UB
  #ifdef _DEBUG
    #ifdef _WIN64
      static const wchar_t* s_dllName = L"starlight_ub_x64_UB Debug.dll";
    #else
      static const wchar_t* s_dllName = L"starlight_ub_Win32_UB Debug.dll";
    #endif
  #endif
#else
  #ifdef _DEBUG
    #ifdef _WIN64
      static const wchar_t* s_dllName = L"starlight_x64_Debug.dll";
    #else
      static const wchar_t* s_dllName = L"starlight_Win32_Debug.dll";
    #endif
  #endif
#endif

// Globals
static std::mutex s_mutex;
static graphics::API* g_renderApi;

static HWND s_hwnd = nullptr;
static util::ThreadSafeQueue<WindowEvent>* s_queue;
static std::atomic_bool s_running;

static LARGE_INTEGER s_lastTime;
static LARGE_INTEGER s_perfFreq;

static GameFuncs s_gameFuncs;

// This is ugly
#ifdef STARLIGHT_D3D11
static graphics::D3D11 d3d11;
#endif
#ifdef STARLIGHT_D3D10
static graphics::D3D10 d3d10;
#endif

CALCULATE_DELTA_TIME(CalculateDeltaTime) {
	LARGE_INTEGER currentTime;
	QueryPerformanceCounter(&currentTime);
	float deltaTime = float(currentTime.QuadPart - s_lastTime.QuadPart) / float(s_perfFreq.QuadPart);
	s_lastTime = currentTime;
	return deltaTime;
}

GameFuncs LoadGameFuncs() {
	GameFuncs gameFuncs;
	ZERO_MEM(&gameFuncs, sizeof(GameFuncs));

#if _DEBUG
	HMODULE lib = LoadLibraryW(s_dllName);
	if (!lib) {
		GetLastError();
	}
	else {
		gameFuncs.DestroyGame = (DestroyGameFunc*) GetProcAddress(lib, "DestroyGame");
		gameFuncs.UpdateGame = (UpdateGameFunc*) GetProcAddress(lib, "UpdateGame");
		gameFuncs.InitLogger = (InitLoggerFunc*) GetProcAddress(lib, "InitLogger");
		gameFuncs.DestroyLogger = (DestroyLoggerFunc*) GetProcAddress(lib, "DestroyLogger");
		gameFuncs.LogInfo = (LogInfoFunc*) GetProcAddress(lib, "LogInfo");
		if (!(gameFuncs.DestroyGame
			&& gameFuncs.UpdateGame
			&& gameFuncs.InitLogger
			&& gameFuncs.DestroyLogger
			&& gameFuncs.LogInfo)) {
			GetLastError();
		}
	}
#else
	gameFuncs.DestroyGame = game::DestroyGame;
	gameFuncs.UpdateGame = game::UpdateGame;
	gameFuncs.InitLogger = logger::InitLogger;
	gameFuncs.DestroyLogger = logger::DestroyLogger;
	gameFuncs.LogInfo = logger::LogInfo;
#endif

	return gameFuncs;
}

// Try to initialize the specified rendering API.
// TODO: Remove globals for the APIs
// If it fails, it returns false.
bool LoadRenderApiImpl(EGraphicsApi e) {
	graphics::API* api = nullptr;
	switch (e) {
#ifdef STARLIGHT_D3D10
	case D3D10:
		logger::LogInfo("Loading D3D10...");
		api = &d3d10;
		break;
#endif
#ifdef STARLIGHT_D3D11
	case D3D11:
		s_gameFuncs.LogInfo("Loading D3D11...");
		api = &d3d11;
		break;
#endif
	default:
		s_gameFuncs.LogInfo("The requested graphics API is not enabled.");
		return false;
	}

	// Cannot init if there is no window
	assert(s_hwnd);

	PlatformData platformData;
	ZeroMemory(&platformData, sizeof(platformData));
	platformData.hWnd = s_hwnd;

#if 1
	// Init new -> destroy old
	if (api->Init(&platformData, &s_gameFuncs)) {
		if (g_renderApi) {
			g_renderApi->Destroy();
		}
		g_renderApi = api;

		// Reload fonts
		ImGuiIO& io = ImGui::GetIO();
		io.Fonts->Clear();
		io.Fonts->AddFontFromFileTTF("assets/DroidSans.ttf", 14.0f, nullptr, io.Fonts->GetGlyphRangesCyrillic());
		return true;
	}
#else
	// Destroy old -> init new
	if (g_renderApi) {
		g_renderApi->Destroy();
		g_renderApi = nullptr;
	}
	if (api->Init(&platformData)) {
		g_renderApi = api;
		return true;
	}

#endif
	return false;
}

#if 0
class HeapArea
{
public:
	explicit HeapArea(std::size_t bytes) {
		start = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	}

	~HeapArea() {
		VirtualFree(start, 0, MEM_RELEASE);
	}

	void* GetStart() { return start; }
	void* GetEnd() { return end; }

private:
	void* start;
	void* end;
};

static HeapArea* heapArea;

void* CALLBACK LibMalloc(std::size_t size) {
	return nullptr;
}

void CALLBACK LibFree(void* ptr) {

}
#endif

void ParseMessages() {
	WindowEvent message;
	// Clear queue for now
	// TODO: Process input
	while (s_queue->Dequeue(&message)) {}
}

void MyThreadFunction() {
	EGraphicsApi graphicsApi = EGraphicsApi::D3D11;
	if (!LoadRenderApiImpl(graphicsApi)) {
		s_running.store(false);
		return;
	}

	// Init time
	QueryPerformanceFrequency(&s_perfFreq);
	QueryPerformanceCounter(&s_lastTime);

	GameInfo gameInfo;
	ZeroMemory(&gameInfo, sizeof(gameInfo));
	gameInfo.graphicsApi = graphicsApi;
	gameInfo.imguiState = ImGui::GetInternalState();
	//heapArea = new HeapArea(512 * 1024 * 1024);
	//memory::SimpleArena arena(heapArea);
	//gameInfo.allocator = &arena;
	gameInfo.CalculateDeltaTime = CalculateDeltaTime;

	// ENet
#if 0
	ENetCallbacks callbacks;
	ZERO_MEM(&callbacks, sizeof(callbacks));
	callbacks.malloc = memory::malloc;
	callbacks.free = memory::free;
	callbacks.no_memory = memory::no_memory;

	if (enet_initialize_with_callbacks(ENET_VERSION, &callbacks) != 0)
#endif
	if (enet_initialize() != 0)
	{
		s_running.store(false);
		return;
	}

	// Main loop
	while (s_running.load())
	{
		// Check if graphics API change was requested
		if (gameInfo.graphicsApi != graphicsApi) {
			if (LoadRenderApiImpl(gameInfo.graphicsApi)) {
				graphicsApi = gameInfo.graphicsApi;
			} else {
				gameInfo.graphicsApi = graphicsApi;
			}
		}

		ParseMessages();

		g_renderApi->ImGuiNewFrame();

		s_gameFuncs.UpdateGame(&gameInfo, g_renderApi);

		// Rendering
		if (std::try_lock(s_mutex)) {
			g_renderApi->Render();
			s_mutex.unlock();
		}
	}

	s_gameFuncs.DestroyGame();
	g_renderApi->Destroy();
	ImGui::Shutdown();
	g_renderApi = nullptr;

	//delete heapArea;

	enet_deinitialize();
}

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	WindowEvent params;
	ZeroMemory(&params, sizeof(params));
	params.hWnd = hWnd;
	params.msg = msg;
	params.wParam = wParam;
	params.lParam = lParam;

	s_queue->Enqueue(params);

	if (g_renderApi && g_renderApi->ImGuiHandleEvent(&params))
		return true;

	switch (msg)
	{
	case WM_SIZE:
		if (g_renderApi && wParam != SIZE_MINIMIZED) {
			g_renderApi->Resize((int32_t) LOWORD(lParam), (int32_t) HIWORD(lParam));
			//return 0;
		}
		break;
	case WM_SYSCOMMAND:
		if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
			return 0;
		break;
	case WM_DESTROY:
		s_running.store(false);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProcW(hWnd, msg, wParam, lParam);
}

int CALLBACK WinMain(
	HINSTANCE   hInstance,
	HINSTANCE   hPrevInstance,
	LPSTR       lpCmdLine,
	int         nCmdShow)
{
	//std::set_new_handler(memory::no_memory);

	s_gameFuncs = LoadGameFuncs();

	ImGuiIO& io = ImGui::GetIO();
	//io.MemAllocFn = memory::malloc;
	//io.MemFreeFn = memory::free;

	//_crtBreakAlloc = 4015;
	s_queue = new util::ThreadSafeQueue<WindowEvent>();

	s_gameFuncs.InitLogger();

	s_gameFuncs.LogInfo(SL_BUILD_DATE);

	auto className = L"StarlightClassName";

	WNDCLASSEXW wndClass = { 0 };
	wndClass.cbSize = sizeof(WNDCLASSEXW);
	wndClass.style = CS_CLASSDC;
	wndClass.lpfnWndProc = WndProc;
	wndClass.hInstance = GetModuleHandleW(nullptr);
	wndClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
	wndClass.lpszClassName = className;

	RegisterClassExW(&wndClass);

	// Get desktop rectangle
	RECT desktopRect;
	GetClientRect(GetDesktopWindow(), &desktopRect);

	// Get window rectangle
	RECT windowRect = { 0, 0, 800, 600 }; // TODO: Config file?
	AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);

	// Calculate window dimensions
	auto windowWidth = windowRect.right - windowRect.left;
	auto windowHeight = windowRect.bottom - windowRect.top;

	s_hwnd = CreateWindowExW(
		0L,
		className,
		L"Starlight",
		WS_OVERLAPPEDWINDOW,
		desktopRect.right / 2 - windowWidth / 2,
		desktopRect.bottom / 2 - windowHeight / 2,
		windowWidth,
		windowHeight,
		nullptr,
		nullptr,
		GetModuleHandleW(nullptr),
		nullptr
		);

	// Show the window
	ShowWindow(s_hwnd, SW_SHOWDEFAULT);
	UpdateWindow(s_hwnd);

	// Create thread
	s_running.store(true);
	std::thread thread(MyThreadFunction);

	// Message loop
	MSG msg;
	while (s_running.load() && GetMessageW(&msg, nullptr, 0, 0))
	{
		std::lock_guard<std::mutex> lock(s_mutex);
		TranslateMessage(&msg);
		DispatchMessageW(&msg);
	}

	thread.join();

	s_gameFuncs.DestroyLogger();

	io.Fonts->Clear();

	delete s_queue;

	UnregisterClassW(className, GetModuleHandleW(nullptr));

	_CrtDumpMemoryLeaks();
}

#if 0

// Global memory functions

void* MEM_CALL operator new(std::size_t n) throw() {
	return memory::malloc(n);
}

void* MEM_CALL operator new[](std::size_t s) throw() {
	return operator new(s);
}

void MEM_CALL operator delete(void * p) throw() {
	return memory::free(p);
}

void MEM_CALL operator delete[](void *p) throw() {
	return operator delete(p);
}

// Wrappers

void* MEM_CALL memory::malloc(std::size_t size) {
	return ::malloc(size);
}

void MEM_CALL memory::free(void* ptr) {
	return ::free(ptr);
}

void* MEM_CALL memory::realloc(void* ptr, std::size_t size) {
	return ::realloc(ptr, size);
}

void MEM_CALL memory::no_memory() {

}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: db.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlhelp.hxx"

#include "db.hxx"

#include <rtl/alloc.h>
#include <cstring>

namespace berkeleydbproxy {

//----------------------------------------------------------------------------
    namespace db_internal
    {
        // static void raise_error(int dberr, const char * where);

        static inline int check_error(int dberr, const char * where)
        {
            (void)where;

            // if (dberr) raise_error(dberr,where);
            return dberr;
        }
    }

//----------------------------------------------------------------------------

int Db::set_alloc(   db_malloc_fcn_type app_malloc,
                     db_realloc_fcn_type app_realloc,
                     db_free_fcn_type app_free)
{
    int err = m_pDBP->set_alloc(m_pDBP,app_malloc,app_realloc,app_free);
    return db_internal::check_error(err,"Db::set_alloc");
}

Db::Db()
{
    db_internal::check_error( db_create(&m_pDBP,0,0),"Db::Db" );
}

Db::~Db()
{
    if (m_pDBP)
    {
        // should not happen
        // TODO: add assert
    }

}

int Db::close(u_int32_t flags)
{
    int error = m_pDBP->close(m_pDBP,flags);
    m_pDBP = 0;
    return db_internal::check_error(error,"Db::close");
}

int Db::open(DB_TXN *txnid,
             const char *file,
             const char *database,
             DBTYPE type,
             u_int32_t flags,
             int mode)
{
    int err = m_pDBP->open(m_pDBP,txnid,file,database,type,flags,mode);
    return db_internal::check_error( err,"Db::open" );
}

int Db::get(DB_TXN *txnid, Dbt *key, Dbt *data, u_int32_t flags)
{
    int err = m_pDBP->get(m_pDBP,txnid,key,data,flags);

    // these are non-exceptional outcomes
    if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
        db_internal::check_error( err,"Db::get" );

    return err;
}

int Db::put(DB_TXN* txnid, Dbt *key, Dbt *data, u_int32_t flags)
{
    int err = m_pDBP->put(m_pDBP,txnid,key,data,flags);

    if (err != DB_KEYEXIST) // this is a non-exceptional outcome
        db_internal::check_error( err,"Db::put" );
    return err;
}

int Db::cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags)
{
    DBC * dbc = 0;
    int error = m_pDBP->cursor(m_pDBP,txnid,&dbc,flags);

    if (!db_internal::check_error(error,"Db::cursor"))
        *cursorp = new Dbc(dbc);

    return error;
}

//----------------------------------------------------------------------------

Dbc::Dbc(DBC * dbc)
: m_pDBC(dbc)
{
}

Dbc::~Dbc()
{
}

int Dbc::close()
{
    int err = m_pDBC->c_close(m_pDBC);
    delete this;
    return db_internal::check_error( err,"Dbcursor::close" );
}

int Dbc::get(Dbt *key, Dbt *data, u_int32_t flags)
{
    int err = m_pDBC->c_get(m_pDBC,key,data,flags);

    // these are non-exceptional outcomes
    if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
        db_internal::check_error( err, "Dbcursor::get" );

    return err;
}

//----------------------------------------------------------------------------

Dbt::Dbt()
{
    using namespace std;
    DBT * thispod = this;
    memset(thispod, 0, sizeof *thispod);
}

Dbt::Dbt(void *data_arg, u_int32_t size_arg)
{
    using namespace std;
    DBT * thispod = this;
    memset(thispod, 0, sizeof *thispod);
    this->set_data(data_arg);
    this->set_size(size_arg);
}

Dbt::Dbt(const Dbt & other)
{
    using namespace std;
    const DBT *otherpod = &other;
    DBT *thispod = this;
    memcpy(thispod, otherpod, sizeof *thispod);
}

Dbt& Dbt::operator = (const Dbt & other)
{
    if (this != &other)
    {
        using namespace std;
        const DBT *otherpod = &other;
        DBT *thispod = this;
        memcpy(thispod, otherpod, sizeof *thispod);
    }
    return *this;
}

Dbt::~Dbt()
{
}

void * Dbt::get_data() const
{
    return this->data;
}

void Dbt::set_data(void *value)
{
    this->data = value;
}

u_int32_t Dbt::get_size() const
{
    return this->size;
}

void Dbt::set_size(u_int32_t value)
{
    this->size = value;
}

void Dbt::set_flags(u_int32_t value)
{
    this->flags = value;
}

//----------------------------------------------------------------------------
/*
void db_internal::raise_error(int dberr, const char * where)
{
    if (!where) where = "<unknown>";

    const char * dberrmsg = db_strerror(dberr);
    if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>";

    rtl::OString msg = where;
    msg += ": ";
    msg += dberrmsg;

    throw DbException(msg);
}
*/

//----------------------------------------------------------------------------
} // namespace ecomp

<commit_msg>INTEGRATION: CWS ab52 (1.7.6); FILE MERGED 2008/06/18 09:23:23 ab 1.7.6.1: #i90029# Removed unused code<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: db.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlhelp.hxx"

#include "db.hxx"

#include <rtl/alloc.h>
#include <cstring>

namespace berkeleydbproxy {

//----------------------------------------------------------------------------
    namespace db_internal
    {
        // static void raise_error(int dberr, const char * where);

        static inline int check_error(int dberr, const char * where)
        {
            (void)where;

            // if (dberr) raise_error(dberr,where);
            return dberr;
        }
    }

Db::Db()
{
    db_internal::check_error( db_create(&m_pDBP,0,0),"Db::Db" );
}

Db::~Db()
{
    if (m_pDBP)
    {
        // should not happen
        // TODO: add assert
    }

}

int Db::close(u_int32_t flags)
{
    int error = m_pDBP->close(m_pDBP,flags);
    m_pDBP = 0;
    return db_internal::check_error(error,"Db::close");
}

int Db::open(DB_TXN *txnid,
             const char *file,
             const char *database,
             DBTYPE type,
             u_int32_t flags,
             int mode)
{
    int err = m_pDBP->open(m_pDBP,txnid,file,database,type,flags,mode);
    return db_internal::check_error( err,"Db::open" );
}

int Db::get(DB_TXN *txnid, Dbt *key, Dbt *data, u_int32_t flags)
{
    int err = m_pDBP->get(m_pDBP,txnid,key,data,flags);

    // these are non-exceptional outcomes
    if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
        db_internal::check_error( err,"Db::get" );

    return err;
}

int Db::cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags)
{
    DBC * dbc = 0;
    int error = m_pDBP->cursor(m_pDBP,txnid,&dbc,flags);

    if (!db_internal::check_error(error,"Db::cursor"))
        *cursorp = new Dbc(dbc);

    return error;
}

//----------------------------------------------------------------------------

Dbc::Dbc(DBC * dbc)
: m_pDBC(dbc)
{
}

Dbc::~Dbc()
{
}

int Dbc::close()
{
    int err = m_pDBC->c_close(m_pDBC);
    delete this;
    return db_internal::check_error( err,"Dbcursor::close" );
}

int Dbc::get(Dbt *key, Dbt *data, u_int32_t flags)
{
    int err = m_pDBC->c_get(m_pDBC,key,data,flags);

    // these are non-exceptional outcomes
    if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
        db_internal::check_error( err, "Dbcursor::get" );

    return err;
}

//----------------------------------------------------------------------------

Dbt::Dbt()
{
    using namespace std;
    DBT * thispod = this;
    memset(thispod, 0, sizeof *thispod);
}

Dbt::Dbt(void *data_arg, u_int32_t size_arg)
{
    using namespace std;
    DBT * thispod = this;
    memset(thispod, 0, sizeof *thispod);
    this->set_data(data_arg);
    this->set_size(size_arg);
}

Dbt::Dbt(const Dbt & other)
{
    using namespace std;
    const DBT *otherpod = &other;
    DBT *thispod = this;
    memcpy(thispod, otherpod, sizeof *thispod);
}

Dbt& Dbt::operator = (const Dbt & other)
{
    if (this != &other)
    {
        using namespace std;
        const DBT *otherpod = &other;
        DBT *thispod = this;
        memcpy(thispod, otherpod, sizeof *thispod);
    }
    return *this;
}

Dbt::~Dbt()
{
}

void * Dbt::get_data() const
{
    return this->data;
}

void Dbt::set_data(void *value)
{
    this->data = value;
}

u_int32_t Dbt::get_size() const
{
    return this->size;
}

void Dbt::set_size(u_int32_t value)
{
    this->size = value;
}

void Dbt::set_flags(u_int32_t value)
{
    this->flags = value;
}

//----------------------------------------------------------------------------
/*
void db_internal::raise_error(int dberr, const char * where)
{
    if (!where) where = "<unknown>";

    const char * dberrmsg = db_strerror(dberr);
    if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>";

    rtl::OString msg = where;
    msg += ": ";
    msg += dberrmsg;

    throw DbException(msg);
}
*/

//----------------------------------------------------------------------------
} // namespace ecomp

<|endoftext|>


<commit_before>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: geom/LineString.java r320 (JTS-1.12)
 *
 **********************************************************************/

#include <geos/util/IllegalArgumentException.h>
#include <geos/algorithm/Length.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFilter.h>
#include <geos/geom/CoordinateFilter.h>
#include <geos/geom/Dimension.h>
#include <geos/geom/GeometryFilter.h>
#include <geos/geom/GeometryComponentFilter.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/LineString.h>
#include <geos/geom/Point.h>
#include <geos/geom/MultiPoint.h> // for getBoundary
#include <geos/geom/Envelope.h>

#include <algorithm>
#include <typeinfo>
#include <memory>
#include <cassert>

using namespace std;
using namespace geos::algorithm;

namespace geos {
namespace geom { // geos::geom

/*protected*/
LineString::LineString(const LineString& ls)
    :
    Geometry(ls),
    points(ls.points->clone())
{
    //points=ls.points->clone();
}

std::unique_ptr<Geometry>
LineString::reverse() const
{
    if(isEmpty()) {
        return clone();
    }

    assert(points.get());
    auto seq = points->clone();
    CoordinateSequence::reverse(seq.get());
    assert(getFactory());
    return std::unique_ptr<Geometry>(getFactory()->createLineString(seq.release()));
}

/*private*/
void
LineString::validateConstruction()
{
    if(points.get() == nullptr) {
        points = getFactory()->getCoordinateSequenceFactory()->create();
        return;
    }

    if(points->size() == 1) {
        throw util::IllegalArgumentException("point array must contain 0 or >1 elements\n");
    }
}

/*protected*/
LineString::LineString(CoordinateSequence* newCoords,
                       const GeometryFactory* factory)
    :
    Geometry(factory),
    points(newCoords)
{
    validateConstruction();
}

/*public*/
LineString::LineString(CoordinateSequence::Ptr && newCoords,
                       const GeometryFactory& factory)
    :
    Geometry(&factory),
    points(std::move(newCoords))
{
    validateConstruction();
}

std::unique_ptr<CoordinateSequence>
LineString::getCoordinates() const
{
    assert(points.get());
    return points->clone();
    //return points;
}

const CoordinateSequence*
LineString::getCoordinatesRO() const
{
    assert(nullptr != points.get());
    return points.get();
}

const Coordinate&
LineString::getCoordinateN(size_t n) const
{
    assert(points.get());
    return points->getAt(n);
}

Dimension::DimensionType
LineString::getDimension() const
{
    return Dimension::L; // line
}

int
LineString::getCoordinateDimension() const
{
    return (int) points->getDimension();
}

int
LineString::getBoundaryDimension() const
{
    if(isClosed()) {
        return Dimension::False;
    }
    return 0;
}

bool
LineString::isEmpty() const
{
    assert(points.get());
    return points->isEmpty();
}

size_t
LineString::getNumPoints() const
{
    assert(points.get());
    return points->getSize();
}

std::unique_ptr<Point>
LineString::getPointN(size_t n) const
{
    assert(getFactory());
    assert(points.get());
    return std::unique_ptr<Point>(getFactory()->createPoint(points->getAt(n)));
}

std::unique_ptr<Point>
LineString::getStartPoint() const
{
    if(isEmpty()) {
        return nullptr;
        //return new Point(NULL,NULL);
    }
    return getPointN(0);
}

std::unique_ptr<Point>
LineString::getEndPoint() const
{
    if(isEmpty()) {
        return nullptr;
        //return new Point(NULL,NULL);
    }
    return getPointN(getNumPoints() - 1);
}

bool
LineString::isClosed() const
{
    if(isEmpty()) {
        return false;
    }
    return getCoordinateN(0).equals2D(getCoordinateN(getNumPoints() - 1));
}

bool
LineString::isRing() const
{
    return isClosed() && isSimple();
}

string
LineString::getGeometryType() const
{
    return "LineString";
}

std::unique_ptr<Geometry>
LineString::getBoundary() const
{
    if(isEmpty()) {
        return std::unique_ptr<Geometry>(getFactory()->createMultiPoint());
    }

    // using the default OGC_SFS MOD2 rule, the boundary of a
    // closed LineString is empty
    if(isClosed()) {
        return std::unique_ptr<Geometry>(getFactory()->createMultiPoint());
    }
    std::vector<std::unique_ptr<Point>> pts(2);
    pts[0] = getStartPoint();
    pts[1] = getEndPoint();
    return getFactory()->createMultiPoint(std::move(pts));
}

bool
LineString::isCoordinate(Coordinate& pt) const
{
    assert(points.get());
    std::size_t npts = points->getSize();
    for(std::size_t i = 0; i < npts; i++) {
        if(points->getAt(i) == pt) {
            return true;
        }
    }
    return false;
}

/*protected*/
Envelope::Ptr
LineString::computeEnvelopeInternal() const
{
    if(isEmpty()) {
        // We don't return NULL here
        // as it would indicate "unknown"
        // envelope. In this case we
        // *know* the envelope is EMPTY.
        return Envelope::Ptr(new Envelope());
    }

    assert(points.get());
    const Coordinate& c = points->getAt(0);
    double minx = c.x;
    double miny = c.y;
    double maxx = c.x;
    double maxy = c.y;
    std::size_t npts = points->getSize();
    for(std::size_t i = 1; i < npts; i++) {
        const Coordinate& c1 = points->getAt(i);
        minx = minx < c1.x ? minx : c1.x;
        maxx = maxx > c1.x ? maxx : c1.x;
        miny = miny < c1.y ? miny : c1.y;
        maxy = maxy > c1.y ? maxy : c1.y;
    }

    // caller expects a newly allocated Envelope.
    // this function won't be called twice, unless
    // cached Envelope is invalidated (set to NULL)
    return Envelope::Ptr(new Envelope(minx, maxx, miny, maxy));
}

bool
LineString::equalsExact(const Geometry* other, double tolerance) const
{
    if(!isEquivalentClass(other)) {
        return false;
    }

    const LineString* otherLineString = dynamic_cast<const LineString*>(other);
    assert(otherLineString);
    size_t npts = points->getSize();
    if(npts != otherLineString->points->getSize()) {
        return false;
    }
    for(size_t i = 0; i < npts; ++i) {
        if(!equal(points->getAt(i), otherLineString->points->getAt(i), tolerance)) {
            return false;
        }
    }
    return true;
}

void
LineString::apply_rw(const CoordinateFilter* filter)
{
    assert(points.get());
    points->apply_rw(filter);
}

void
LineString::apply_ro(CoordinateFilter* filter) const
{
    assert(points.get());
    points->apply_ro(filter);
}

void
LineString::apply_rw(GeometryFilter* filter)
{
    assert(filter);
    filter->filter_rw(this);
}

void
LineString::apply_ro(GeometryFilter* filter) const
{
    assert(filter);
    filter->filter_ro(this);
}

/*public*/
void
LineString::normalize()
{
    assert(points.get());
    std::size_t npts = points->getSize();
    std::size_t n = npts / 2;
    for(std::size_t i = 0; i < n; i++) {
        std::size_t j = npts - 1 - i;
        if(!(points->getAt(i) == points->getAt(j))) {
            if(points->getAt(i).compareTo(points->getAt(j)) > 0) {
                CoordinateSequence::reverse(points.get());
            }
            return;
        }
    }
}

int
LineString::compareToSameClass(const Geometry* ls) const
{
    const LineString* line = dynamic_cast<const LineString*>(ls);
    assert(line);
    // MD - optimized implementation
    std::size_t mynpts = points->getSize();
    std::size_t othnpts = line->points->getSize();
    if(mynpts > othnpts) {
        return 1;
    }
    if(mynpts < othnpts) {
        return -1;
    }
    for(std::size_t i = 0; i < mynpts; i++) {
        int cmp = points->getAt(i).compareTo(line->points->getAt(i));
        if(cmp) {
            return cmp;
        }
    }
    return 0;
}

const Coordinate*
LineString::getCoordinate() const
{
    if(isEmpty()) {
        return nullptr;
    }
    return &(points->getAt(0));
}

double
LineString::getLength() const
{
    return Length::ofLine(points.get());
}

void
LineString::apply_rw(GeometryComponentFilter* filter)
{
    assert(filter);
    filter->filter_rw(this);
}

void
LineString::apply_ro(GeometryComponentFilter* filter) const
{
    assert(filter);
    filter->filter_ro(this);
}

void
LineString::apply_rw(CoordinateSequenceFilter& filter)
{
    size_t npts = points->size();
    if(!npts) {
        return;
    }
    for(size_t i = 0; i < npts; ++i) {
        filter.filter_rw(*points, i);
        if(filter.isDone()) {
            break;
        }
    }
    if(filter.isGeometryChanged()) {
        geometryChanged();
    }
}

void
LineString::apply_ro(CoordinateSequenceFilter& filter) const
{
    size_t npts = points->size();
    if(!npts) {
        return;
    }
    for(size_t i = 0; i < npts; ++i) {
        filter.filter_ro(*points, i);
        if(filter.isDone()) {
            break;
        }
    }
    //if (filter.isGeometryChanged()) geometryChanged();
}

GeometryTypeId
LineString::getGeometryTypeId() const
{
    return GEOS_LINESTRING;
}

} // namespace geos::geom
} // namespace geos
<commit_msg>Optimize LineString::computeEnvelopeInternal<commit_after>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: geom/LineString.java r320 (JTS-1.12)
 *
 **********************************************************************/

#include <geos/util/IllegalArgumentException.h>
#include <geos/algorithm/Length.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFilter.h>
#include <geos/geom/CoordinateFilter.h>
#include <geos/geom/Dimension.h>
#include <geos/geom/GeometryFilter.h>
#include <geos/geom/GeometryComponentFilter.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/LineString.h>
#include <geos/geom/Point.h>
#include <geos/geom/MultiPoint.h> // for getBoundary
#include <geos/geom/Envelope.h>

#include <algorithm>
#include <typeinfo>
#include <memory>
#include <cassert>

using namespace std;
using namespace geos::algorithm;

namespace geos {
namespace geom { // geos::geom

/*protected*/
LineString::LineString(const LineString& ls)
    :
    Geometry(ls),
    points(ls.points->clone())
{
    //points=ls.points->clone();
}

std::unique_ptr<Geometry>
LineString::reverse() const
{
    if(isEmpty()) {
        return clone();
    }

    assert(points.get());
    auto seq = points->clone();
    CoordinateSequence::reverse(seq.get());
    assert(getFactory());
    return std::unique_ptr<Geometry>(getFactory()->createLineString(seq.release()));
}

/*private*/
void
LineString::validateConstruction()
{
    if(points.get() == nullptr) {
        points = getFactory()->getCoordinateSequenceFactory()->create();
        return;
    }

    if(points->size() == 1) {
        throw util::IllegalArgumentException("point array must contain 0 or >1 elements\n");
    }
}

/*protected*/
LineString::LineString(CoordinateSequence* newCoords,
                       const GeometryFactory* factory)
    :
    Geometry(factory),
    points(newCoords)
{
    validateConstruction();
}

/*public*/
LineString::LineString(CoordinateSequence::Ptr && newCoords,
                       const GeometryFactory& factory)
    :
    Geometry(&factory),
    points(std::move(newCoords))
{
    validateConstruction();
}

std::unique_ptr<CoordinateSequence>
LineString::getCoordinates() const
{
    assert(points.get());
    return points->clone();
    //return points;
}

const CoordinateSequence*
LineString::getCoordinatesRO() const
{
    assert(nullptr != points.get());
    return points.get();
}

const Coordinate&
LineString::getCoordinateN(size_t n) const
{
    assert(points.get());
    return points->getAt(n);
}

Dimension::DimensionType
LineString::getDimension() const
{
    return Dimension::L; // line
}

int
LineString::getCoordinateDimension() const
{
    return (int) points->getDimension();
}

int
LineString::getBoundaryDimension() const
{
    if(isClosed()) {
        return Dimension::False;
    }
    return 0;
}

bool
LineString::isEmpty() const
{
    assert(points.get());
    return points->isEmpty();
}

size_t
LineString::getNumPoints() const
{
    assert(points.get());
    return points->getSize();
}

std::unique_ptr<Point>
LineString::getPointN(size_t n) const
{
    assert(getFactory());
    assert(points.get());
    return std::unique_ptr<Point>(getFactory()->createPoint(points->getAt(n)));
}

std::unique_ptr<Point>
LineString::getStartPoint() const
{
    if(isEmpty()) {
        return nullptr;
        //return new Point(NULL,NULL);
    }
    return getPointN(0);
}

std::unique_ptr<Point>
LineString::getEndPoint() const
{
    if(isEmpty()) {
        return nullptr;
        //return new Point(NULL,NULL);
    }
    return getPointN(getNumPoints() - 1);
}

bool
LineString::isClosed() const
{
    if(isEmpty()) {
        return false;
    }
    return getCoordinateN(0).equals2D(getCoordinateN(getNumPoints() - 1));
}

bool
LineString::isRing() const
{
    return isClosed() && isSimple();
}

string
LineString::getGeometryType() const
{
    return "LineString";
}

std::unique_ptr<Geometry>
LineString::getBoundary() const
{
    if(isEmpty()) {
        return std::unique_ptr<Geometry>(getFactory()->createMultiPoint());
    }

    // using the default OGC_SFS MOD2 rule, the boundary of a
    // closed LineString is empty
    if(isClosed()) {
        return std::unique_ptr<Geometry>(getFactory()->createMultiPoint());
    }
    std::vector<std::unique_ptr<Point>> pts(2);
    pts[0] = getStartPoint();
    pts[1] = getEndPoint();
    return getFactory()->createMultiPoint(std::move(pts));
}

bool
LineString::isCoordinate(Coordinate& pt) const
{
    assert(points.get());
    std::size_t npts = points->getSize();
    for(std::size_t i = 0; i < npts; i++) {
        if(points->getAt(i) == pt) {
            return true;
        }
    }
    return false;
}

/*protected*/
Envelope::Ptr
LineString::computeEnvelopeInternal() const
{
    if(isEmpty()) {
        // We don't return NULL here
        // as it would indicate "unknown"
        // envelope. In this case we
        // *know* the envelope is EMPTY.
        return Envelope::Ptr(new Envelope());
    }

    return detail::make_unique<Envelope>(points->getEnvelope());
}

bool
LineString::equalsExact(const Geometry* other, double tolerance) const
{
    if(!isEquivalentClass(other)) {
        return false;
    }

    const LineString* otherLineString = dynamic_cast<const LineString*>(other);
    assert(otherLineString);
    size_t npts = points->getSize();
    if(npts != otherLineString->points->getSize()) {
        return false;
    }
    for(size_t i = 0; i < npts; ++i) {
        if(!equal(points->getAt(i), otherLineString->points->getAt(i), tolerance)) {
            return false;
        }
    }
    return true;
}

void
LineString::apply_rw(const CoordinateFilter* filter)
{
    assert(points.get());
    points->apply_rw(filter);
}

void
LineString::apply_ro(CoordinateFilter* filter) const
{
    assert(points.get());
    points->apply_ro(filter);
}

void
LineString::apply_rw(GeometryFilter* filter)
{
    assert(filter);
    filter->filter_rw(this);
}

void
LineString::apply_ro(GeometryFilter* filter) const
{
    assert(filter);
    filter->filter_ro(this);
}

/*public*/
void
LineString::normalize()
{
    assert(points.get());
    std::size_t npts = points->getSize();
    std::size_t n = npts / 2;
    for(std::size_t i = 0; i < n; i++) {
        std::size_t j = npts - 1 - i;
        if(!(points->getAt(i) == points->getAt(j))) {
            if(points->getAt(i).compareTo(points->getAt(j)) > 0) {
                CoordinateSequence::reverse(points.get());
            }
            return;
        }
    }
}

int
LineString::compareToSameClass(const Geometry* ls) const
{
    const LineString* line = dynamic_cast<const LineString*>(ls);
    assert(line);
    // MD - optimized implementation
    std::size_t mynpts = points->getSize();
    std::size_t othnpts = line->points->getSize();
    if(mynpts > othnpts) {
        return 1;
    }
    if(mynpts < othnpts) {
        return -1;
    }
    for(std::size_t i = 0; i < mynpts; i++) {
        int cmp = points->getAt(i).compareTo(line->points->getAt(i));
        if(cmp) {
            return cmp;
        }
    }
    return 0;
}

const Coordinate*
LineString::getCoordinate() const
{
    if(isEmpty()) {
        return nullptr;
    }
    return &(points->getAt(0));
}

double
LineString::getLength() const
{
    return Length::ofLine(points.get());
}

void
LineString::apply_rw(GeometryComponentFilter* filter)
{
    assert(filter);
    filter->filter_rw(this);
}

void
LineString::apply_ro(GeometryComponentFilter* filter) const
{
    assert(filter);
    filter->filter_ro(this);
}

void
LineString::apply_rw(CoordinateSequenceFilter& filter)
{
    size_t npts = points->size();
    if(!npts) {
        return;
    }
    for(size_t i = 0; i < npts; ++i) {
        filter.filter_rw(*points, i);
        if(filter.isDone()) {
            break;
        }
    }
    if(filter.isGeometryChanged()) {
        geometryChanged();
    }
}

void
LineString::apply_ro(CoordinateSequenceFilter& filter) const
{
    size_t npts = points->size();
    if(!npts) {
        return;
    }
    for(size_t i = 0; i < npts; ++i) {
        filter.filter_ro(*points, i);
        if(filter.isDone()) {
            break;
        }
    }
    //if (filter.isGeometryChanged()) geometryChanged();
}

GeometryTypeId
LineString::getGeometryTypeId() const
{
    return GEOS_LINESTRING;
}

} // namespace geos::geom
} // namespace geos
<|endoftext|>


<commit_before>#ifndef NEK_CONTAINER_VECTOR_HPP
#define NEK_CONTAINER_VECTOR_HPP

#include <cassert>
#include <initializer_list>
#include <stdexcept>

#include <algorithm> // TODO : std::max
#include <nek/algorithm/rotate.hpp>
#include <nek/container/function.hpp>
#include <nek/detail/destroy.hpp>
#include <nek/allocator/allocator.hpp>
#include <nek/allocator/allocator_traits.hpp>
#include <nek/iterator/distance.hpp>
#include <nek/iterator/iterator_traits.hpp>
#include <nek/iterator/move_iterator.hpp>
#include <nek/iterator/normal_iterator.hpp>
#include <nek/uninitialized/uninitialized_copy.hpp>
#include <nek/uninitialized/uninitialized_default.hpp>
#include <nek/utility/forward.hpp>
#include <nek/utility/swap.hpp>
#include <vector>

namespace nek
{
  namespace vector_detail
  {
    template <class T, class Allocator>
    class vector_base
      : private nek::allocator_traits<Allocator>::template rebind_alloc<T>
    {
    protected:
      using base_type = typename nek::allocator_traits<Allocator>::template rebind_alloc<T>;
      using alloc_type = base_type; // NOTE : workaround. base_type::base_type is not allowed.
      using pointer = typename nek::allocator_traits<alloc_type>::pointer;
      using size_type = typename nek::allocator_traits<alloc_type>::size_type;

    private:
      pointer first_; // head pointer to reserved and initialized storage
      pointer last_; // initialized storage end
      pointer capacity_end_; // reserved storage end

      void reserve(size_type count)
      {
        first_ = base_type::allocate(count);
        last_ = first_;
        capacity_end_ = first_ + count;
      }

    protected:
      pointer& first() noexcept
      {
        return first_;
      }

      pointer const& first() const noexcept
      {
        return first_;
      }

      pointer& last() noexcept
      {
        return last_;
      }

      pointer const& last() const noexcept
      {
        return last_;
      }

      pointer& capacity_end() noexcept
      {
        return capacity_end_;
      }

      pointer const& capacity_end() const noexcept
      {
        return capacity_end_;
      }

      alloc_type& allocator() noexcept
      {
        return *(static_cast<alloc_type*>(this));
      }

      alloc_type const& allocator() const noexcept
      {
        return *(static_cast<alloc_type const*>(this));
      }

    public:
      vector_base()
        : base_type{},
        first_{nullptr},
        last_{nullptr},
        capacity_end_{nullptr}
      {
      }

      explicit vector_base(Allocator const& allocator)
        : base_type{allocator},
        first_{nullptr},
        last_{nullptr},
        capacity_end_{nullptr}
      {
      }

      explicit vector_base(size_type count)
        : base_type{}
      {
        reserve(count);
      }

      vector_base(size_type count, Allocator const& allocator)
        : base_type{allocator}
      {
        reserve(count);
      }

      ~vector_base()
      {
        if (first_) {
          base_type::deallocate(first_, capacity_end_ - first_);
        }
      }
    };
  }

  template <class T, class Allocator = nek::allocator<T>>
  class vector
    : private vector_detail::vector_base<T, Allocator>
  {
    using base_type = vector_detail::vector_base<T, Allocator>;
    using alloc_traits = nek::allocator_traits<typename base_type::alloc_type>;

    static constexpr inline double rate() noexcept
    {
      return 1.5;
    }

    template <class InputIterator>
    void range_initialize(InputIterator first, InputIterator last, std::input_iterator_tag)
    {
      for (; first != last; ++first) {
        nek::emplace_back(*this, *first);
      }
    }

    template <class ForwardIterator>
    void range_initialize(ForwardIterator first, ForwardIterator last, std::forward_iterator_tag)
    {
      size_type const count = nek::distance(first, last);
      this->first() = allocator().allocate(count);
      this->capacity_end() = this->first() + count;
      this->last() = nek::uninitialized_copy(first, last, this->first(), allocator());
    }

    template <class Iterator>
    void range_initialize(Iterator first, Iterator last)
    {
      using tag = typename nek::iterator_traits<Iterator>::iterator_category;
      range_initialize(first, last, tag{});
    }

  public:
    using value_type = T;
    using allocator_type = Allocator;
    using size_type = typename base_type::size_type;
    using difference_type = typename alloc_traits::difference_type;
    using reference = T&;
    using const_reference = T const&;
    using pointer = typename base_type::pointer;
    using const_pointer = typename alloc_traits::const_pointer;
    using iterator = normal_iterator<pointer>;
    using const_iterator = normal_iterator<const_pointer>;

    vector()
      : base_type{}
    {
    }

    explicit vector(Allocator const& allocator)
      : base_type{allocator}
    {
    }

    explicit vector(size_type count)
      : base_type{count}
    {
      nek::uninitialized_default_n(first(), count, allocator());
      last() = capacity_end();
    }

    template <class InputIterator>
    vector(InputIterator first, InputIterator last)
      : vector{first, last, allocator_type{}}
    {
    }

    template <class InputIterator>
    vector(InputIterator first, InputIterator last, Allocator const& allocator)
      : base_type{allocator}
    {
      range_initialize(first, last);
    }

    vector(std::initializer_list<value_type> list)
      : vector{list, allocator_type{}}
    {
      range_initialize(list.begin(), list.end(), std::random_access_iterator_tag{});
    }

    vector(std::initializer_list<value_type> list, Allocator const& allocator)
      : base_type{allocator}
    {
      range_initialize(list.begin(), list.end(), std::random_access_iterator_tag{});
    }

    vector(vector const& right)
      : base_type{nek::size(right), alloc_traits::select_on_container_copy_construction(right.get_allocator())}
    {
      last() = nek::uninitialized_copy(right.begin(), right.end(), first());
    }

    ~vector()
    {
      detail::destroy(first(), last(), allocator());
    }

    allocator_type get_allocator() const noexcept
    {
      return allocator_type{allocator()};
    }

    size_type capacity() const noexcept
    {
      return static_cast<size_type>(capacity_end() - first());
    }

    size_type max_size() const noexcept
    {
      return allocator().max_size();
    }

    pointer data() noexcept
    {
      return first();
    }

    const_pointer data() const noexcept
    {
      return first();
    }

    void swap(vector& right)
    {
      using nek::swap;
      swap(first(), right.first());
      swap(last(), right.last());
      swap(capacity_end(), right.capacity_end());
      alloc_traits::swap(allocator(), right.allocator());
    }

    void reserve(size_type count)
    {
      // validate
      if (allocator().max_size() < count) {
        throw std::length_error{"nek::vector<T>::reserve : size is too long."};
      }
      if (count < capacity()) {
        return;
      }

      // allocate new buffer
      pointer new_buffer = allocator().allocate(count);

      size_type const size = nek::size(*this);

      // copy or move new buffer
      try {
        nek::uninitialized_copy(
          nek::make_move_if_noexcept_iterator(first()),
          nek::make_move_if_noexcept_iterator(last()),
          new_buffer, allocator());
      } catch (...) {
        allocator().deallocate(new_buffer, count);
        throw;
      }

      // destruct and deallocate old buffer
      detail::destroy(first(), last(), allocator());
      allocator().deallocate(first(), capacity_end() - first());

      // update pointers
      first() = new_buffer;
      last() = new_buffer + size;
      capacity_end() = new_buffer + count;
    }

    iterator begin() noexcept
    {
      return iterator{first()};
    }

    const_iterator begin() const noexcept
    {
      return const_iterator{first()};
    }

    iterator end() noexcept
    {
      return iterator{last()};
    }

    const_iterator end() const noexcept
    {
      return const_iterator{last()};
    }

    inline reference operator[](size_type n)
    {
      assert(n < nek::size(*this));
      return *(first() + n);
    }

    inline const_reference operator[](size_type n) const
    {
      assert(n < nek::size(*this));
      return *(first() + n);
    }

    template <class InputIterator>
    iterator insert(const_iterator position, InputIterator first, InputIterator last)
    {
    }

    template <class... Args>
    iterator emplace(const_iterator position, Args&&... args)
    {
      auto const diff = position - begin();
      if (last() == capacity_end()) {
        reserve(std::max(static_cast<size_type>(capacity() * rate()), capacity() + 1));
      }
      allocator().construct(last(), nek::forward<Args>(args)...);
      ++last();
      nek::rotate(first() + diff, last() - 1, last());
      return begin() + diff;
    }
  };

  template <class T, class Allocator>
  auto size(vector<T, Allocator> const& v) noexcept
  {
    return static_cast<typename vector<T>::size_type>(v.end() - v.begin());
  }
}

#endif<commit_msg>add insert partial<commit_after>#ifndef NEK_CONTAINER_VECTOR_HPP
#define NEK_CONTAINER_VECTOR_HPP

#include <cassert>
#include <initializer_list>
#include <stdexcept>

#include <algorithm> // TODO : std::max
#include <nek/algorithm/rotate.hpp>
#include <nek/container/function.hpp>
#include <nek/detail/destroy.hpp>
#include <nek/allocator/allocator.hpp>
#include <nek/allocator/allocator_traits.hpp>
#include <nek/iterator/distance.hpp>
#include <nek/iterator/iterator_traits.hpp>
#include <nek/iterator/move_iterator.hpp>
#include <nek/iterator/normal_iterator.hpp>
#include <nek/uninitialized/uninitialized_copy.hpp>
#include <nek/uninitialized/uninitialized_default.hpp>
#include <nek/utility/forward.hpp>
#include <nek/utility/swap.hpp>
#include <vector>

namespace nek
{
  namespace vector_detail
  {
    template <class T, class Allocator>
    class vector_base
      : private nek::allocator_traits<Allocator>::template rebind_alloc<T>
    {
    protected:
      using base_type = typename nek::allocator_traits<Allocator>::template rebind_alloc<T>;
      using alloc_type = base_type; // NOTE : workaround. base_type::base_type is not allowed.
      using pointer = typename nek::allocator_traits<alloc_type>::pointer;
      using size_type = typename nek::allocator_traits<alloc_type>::size_type;

    private:
      pointer first_; // head pointer to reserved and initialized storage
      pointer last_; // initialized storage end
      pointer capacity_end_; // reserved storage end

      void reserve(size_type count)
      {
        first_ = base_type::allocate(count);
        last_ = first_;
        capacity_end_ = first_ + count;
      }

    protected:
      pointer& first() noexcept
      {
        return first_;
      }

      pointer const& first() const noexcept
      {
        return first_;
      }

      pointer& last() noexcept
      {
        return last_;
      }

      pointer const& last() const noexcept
      {
        return last_;
      }

      pointer& capacity_end() noexcept
      {
        return capacity_end_;
      }

      pointer const& capacity_end() const noexcept
      {
        return capacity_end_;
      }

      alloc_type& allocator() noexcept
      {
        return *(static_cast<alloc_type*>(this));
      }

      alloc_type const& allocator() const noexcept
      {
        return *(static_cast<alloc_type const*>(this));
      }

    public:
      vector_base()
        : base_type{},
        first_{nullptr},
        last_{nullptr},
        capacity_end_{nullptr}
      {
      }

      explicit vector_base(Allocator const& allocator)
        : base_type{allocator},
        first_{nullptr},
        last_{nullptr},
        capacity_end_{nullptr}
      {
      }

      explicit vector_base(size_type count)
        : base_type{}
      {
        reserve(count);
      }

      vector_base(size_type count, Allocator const& allocator)
        : base_type{allocator}
      {
        reserve(count);
      }

      ~vector_base()
      {
        if (first_) {
          base_type::deallocate(first_, capacity_end_ - first_);
        }
      }
    };
  }

  template <class T, class Allocator = nek::allocator<T>>
  class vector
    : private vector_detail::vector_base<T, Allocator>
  {
    using base_type = vector_detail::vector_base<T, Allocator>;
    using alloc_traits = nek::allocator_traits<typename base_type::alloc_type>;

  public:
    using value_type = T;
    using allocator_type = Allocator;
    using size_type = typename base_type::size_type;
    using difference_type = typename alloc_traits::difference_type;
    using reference = T&;
    using const_reference = T const&;
    using pointer = typename base_type::pointer;
    using const_pointer = typename alloc_traits::const_pointer;
    using iterator = normal_iterator<pointer>;
    using const_iterator = normal_iterator<const_pointer>;

    vector()
      : base_type{}
    {
    }

    explicit vector(Allocator const& allocator)
      : base_type{allocator}
    {
    }

    explicit vector(size_type count)
      : base_type{count}
    {
      nek::uninitialized_default_n(first(), count, allocator());
      last() = capacity_end();
    }

    template <class InputIterator>
    vector(InputIterator first, InputIterator last)
      : vector{first, last, allocator_type{}}
    {
    }

    template <class InputIterator>
    vector(InputIterator first, InputIterator last, Allocator const& allocator)
      : base_type{allocator}
    {
      range_initialize(first, last);
    }

    vector(std::initializer_list<value_type> list)
      : vector{list, allocator_type{}}
    {
      range_initialize(list.begin(), list.end(), std::random_access_iterator_tag{});
    }

    vector(std::initializer_list<value_type> list, Allocator const& allocator)
      : base_type{allocator}
    {
      range_initialize(list.begin(), list.end(), std::random_access_iterator_tag{});
    }

    vector(vector const& right)
      : base_type{nek::size(right), alloc_traits::select_on_container_copy_construction(right.get_allocator())}
    {
      last() = nek::uninitialized_copy(right.begin(), right.end(), first());
    }

    ~vector()
    {
      detail::destroy(first(), last(), allocator());
    }

    allocator_type get_allocator() const noexcept
    {
      return allocator_type{allocator()};
    }

    size_type capacity() const noexcept
    {
      return static_cast<size_type>(capacity_end() - first());
    }

    size_type max_size() const noexcept
    {
      return allocator().max_size();
    }

    pointer data() noexcept
    {
      return first();
    }

    const_pointer data() const noexcept
    {
      return first();
    }

    void swap(vector& right)
    {
      using nek::swap;
      swap(first(), right.first());
      swap(last(), right.last());
      swap(capacity_end(), right.capacity_end());
      alloc_traits::swap(allocator(), right.allocator());
    }

    void reserve(size_type count)
    {
      // validate
      if (allocator().max_size() < count) {
        throw std::length_error{"nek::vector<T>::reserve : size is too long."};
      }
      if (count < capacity()) {
        return;
      }

      // allocate new buffer
      pointer new_buffer = allocator().allocate(count);

      size_type const size = nek::size(*this);

      // copy or move new buffer
      try {
        nek::uninitialized_copy(
          nek::make_move_if_noexcept_iterator(first()),
          nek::make_move_if_noexcept_iterator(last()),
          new_buffer, allocator());
      } catch (...) {
        allocator().deallocate(new_buffer, count);
        throw;
      }

      // destruct and deallocate old buffer
      detail::destroy(first(), last(), allocator());
      allocator().deallocate(first(), capacity_end() - first());

      // update pointers
      first() = new_buffer;
      last() = new_buffer + size;
      capacity_end() = new_buffer + count;
    }

    iterator begin() noexcept
    {
      return iterator{first()};
    }

    const_iterator begin() const noexcept
    {
      return const_iterator{first()};
    }

    iterator end() noexcept
    {
      return iterator{last()};
    }

    const_iterator end() const noexcept
    {
      return const_iterator{last()};
    }

    inline reference operator[](size_type n)
    {
      assert(n < nek::size(*this));
      return *(first() + n);
    }

    inline const_reference operator[](size_type n) const
    {
      assert(n < nek::size(*this));
      return *(first() + n);
    }

    template <class InputIterator>
    iterator insert(const_iterator position, InputIterator first, InputIterator last)
    {
      using tag = typename nek::iterator_traits<InputIterator>::iterator_category;
      insert_(position, first, last, tag{});
      size_type const pos = position - begin();
      return pos;
    }

    template <class... Args>
    iterator emplace(const_iterator position, Args&&... args)
    {
      auto const diff = position - begin();
      if (last() == capacity_end()) {
        reserve(std::max(static_cast<size_type>(capacity() * rate()), capacity() + 1));
      }
      allocator().construct(last(), nek::forward<Args>(args)...);
      ++last();
      nek::rotate(first() + diff, last() - 1, last());
      return begin() + diff;
    }
    private:
      static constexpr inline double rate() noexcept
      {
        return 1.5;
      }

        template <class InputIterator>
      void range_initialize(InputIterator first, InputIterator last, std::input_iterator_tag)
      {
        for (; first != last; ++first) {
          nek::emplace_back(*this, *first);
        }
      }

      template <class ForwardIterator>
      void range_initialize(ForwardIterator first, ForwardIterator last, std::forward_iterator_tag)
      {
        size_type const count = nek::distance(first, last);
        this->first() = allocator().allocate(count);
        this->capacity_end() = this->first() + count;
        this->last() = nek::uninitialized_copy(first, last, this->first(), allocator());
      }

      template <class Iterator>
      void range_initialize(Iterator first, Iterator last)
      {
        using tag = typename nek::iterator_traits<Iterator>::iterator_category;
        range_initialize(first, last, tag{});
      }

      template <class InputIterator>
      void insert_(const_iterator position, InputIterator first, InputIterator last, std::input_iterator_tag)
      {
        size_type const pos = position - begin();
        size_type const before_size = nek::size(*this);
        try {
          for (; first != last; ++first) {
            emplace(end(), *first);
          }
        } catch (...) {
          // TODO : erase
        }
        nek::rotate(begin() + pos, begin() + before_size, end());
      }
  };

  template <class T, class Allocator>
  auto size(vector<T, Allocator> const& v) noexcept
  {
    return static_cast<typename vector<T>::size_type>(v.end() - v.begin());
  }
}

#endif<|endoftext|>


<commit_before>#include "cpr/timeout.h"

#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace cpr {

long Timeout::Milliseconds() const {
    static_assert(std::is_same<std::chrono::milliseconds, decltype(ms)>::value,
                  "Following casting expects milliseconds.");

    if (ms.count() > std::numeric_limits<long>::max()) {
        throw std::overflow_error("cpr::Timeout: timeout value overflow: " +
                                  std::to_string(ms.count()) + " ms.");
    }
    if (ms.count() < std::numeric_limits<long>::min()) {
        throw std::underflow_error("cpr::Timeout: timeout value underflow: " +
                                   std::to_string(ms.count()) + " ms.");
    }

    return ms.count();
}

} // namespace cpr
<commit_msg>Revert some casts that are needed.<commit_after>#include "cpr/timeout.h"

#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace cpr {

long Timeout::Milliseconds() const {
    static_assert(std::is_same<std::chrono::milliseconds, decltype(ms)>::value,
                  "Following casting expects milliseconds.");

    if (ms.count() > std::numeric_limits<long>::max()) {
        throw std::overflow_error("cpr::Timeout: timeout value overflow: " +
                                  std::to_string(ms.count()) + " ms.");
    }
    if (ms.count() < std::numeric_limits<long>::min()) {
        throw std::underflow_error("cpr::Timeout: timeout value underflow: " +
                                   std::to_string(ms.count()) + " ms.");
    }

    return static_cast<long>(ms.count());
}

} // namespace cpr
<|endoftext|>