<commit_before>/*
===========================================================================
Daemon BSD Source Code
Copyright (c) 2015, Daemon Developers
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Daemon developers nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===========================================================================
*/

#include "common/System.h"
#include "common/String.h"
#include "Crypto.h"
#include <nettle/aes.h>
#include <nettle/base64.h>
#include <nettle/md5.h>
#include <nettle/sha2.h>
#include <nettle/version.h>

// Compatibility with old nettle versions
#if !defined(AES256_KEY_SIZE)

#define AES256_KEY_SIZE 32

typedef aes_ctx compat_aes256_ctx;

static void nettle_compat_aes256_set_encrypt_key(compat_aes256_ctx *ctx, const uint8_t *key)
{
	nettle_aes_set_encrypt_key(ctx, AES256_KEY_SIZE, key);
}

static void nettle_compat_aes256_set_decrypt_key(compat_aes256_ctx *ctx, const uint8_t *key)
{
	nettle_aes_set_decrypt_key(ctx, AES256_KEY_SIZE, key);
}

static void nettle_compat_aes256_encrypt(const compat_aes256_ctx *ctx,
						   size_t length, uint8_t *dst,
						   const uint8_t *src)
{
	nettle_aes_encrypt(ctx, length, dst, src);
}

static void nettle_compat_aes256_decrypt(const compat_aes256_ctx *ctx,
						   size_t length, uint8_t *dst,
						   const uint8_t *src)
{
	nettle_aes_decrypt(ctx, length, dst, src);
}

static int nettle_compat_base64_decode_update(base64_decode_ctx *ctx,
		     size_t *dst_length,
		     uint8_t *dst,
		     size_t src_length,
		     const uint8_t *src)
{
	unsigned dst_length_uns = *dst_length;
	nettle_base64_decode_update(ctx, &dst_length_uns, dst, src_length, src);
}

#undef aes256_set_encrypt_key
#define nettle_aes256_set_encrypt_key nettle_compat_aes256_set_encrypt_key
#define nettle_aes256_set_decrypt_key nettle_compat_aes256_set_decrypt_key
#define nettle_aes256_invert_key      nettle_compat_aes256_invert_key
#define nettle_aes256_encrypt         nettle_compat_aes256_encrypt
#define nettle_aes256_decrypt         nettle_compat_aes256_decrypt
#define aes256_ctx compat_aes256_ctx
#define nettle_base64_decode_update nettle_compat_base64_decode_update

#endif // NETTLE_VERSION_MAJOR < 3

namespace Crypto {

Data RandomData( std::size_t bytes )
{
    Data data( bytes );
    Sys::GenRandomBytes(data.data(), data.size());
    return data;
}

namespace Encoding {

/*
 * Translates binary data into a hexadecimal string
 */
Data HexEncode( const Data& input )
{
    std::ostringstream stream;
    stream.setf(std::ios::hex, std::ios::basefield);
    stream.fill('0');
    for ( auto ch : input )
    {
        stream.width(2);
        stream << int( ch );
    }
    auto string = stream.str();
    return Data(string.begin(), string.end());
}

/*
 * Translates a hexadecimal string into binary data
 * PRE: input is a valid hexadecimal string
 * POST: output contains the decoded string
 * Returns true on success
 * Note: If the decoding fails, output is unchanged
 */
bool HexDecode( const Data& input, Data& output )
{
    if ( input.size() % 2 )
    {
		return false;
    }

    Data mid( input.size() / 2 );

    for ( std::size_t i = 0; i < input.size(); i += 2 )
    {
        if ( !Str::cisxdigit( input[i] ) || !Str::cisxdigit( input[i+1] ) )
        {
            return false;
        }

        mid[ i / 2 ] = ( Str::GetHex( input[i] ) << 4 ) | Str::GetHex( input[i+1] );
    }

    output = mid;
    return true;
}

/*
 * Translates binary data into a base64 encoded string
 */
Data Base64Encode( const Data& input )
{
    base64_encode_ctx ctx;
    nettle_base64_encode_init( &ctx );

    Data output( BASE64_ENCODE_LENGTH( input.size() ) + BASE64_ENCODE_FINAL_LENGTH );
    int encoded_bytes = nettle_base64_encode_update(
        &ctx, output.data(), input.size(), input.data()
    );
    encoded_bytes += nettle_base64_encode_final( &ctx, output.data() + encoded_bytes );
    output.erase( output.begin() + encoded_bytes, output.end() );
    return output;
}

/*
 * Translates a base64 encoded string into binary data
 * PRE: input is a valid Base64 string
 * POST: output contains the decoded string
 * Returns true on success
 * Note: If the decoding fails, output is unchanged
 */
bool Base64Decode( const Data& input, Data& output )
{
    base64_decode_ctx ctx;
    nettle_base64_decode_init( &ctx );

    Data temp( BASE64_DECODE_LENGTH( input.size() ) );
    std::size_t decoded_bytes = 0;
    if ( !nettle_base64_decode_update( &ctx, &decoded_bytes, temp.data(),
                                       input.size(), input.data() ) )
    {
        return false;
    }

    if ( !nettle_base64_decode_final( &ctx ) )
    {
        return false;
    }

    temp.erase( temp.begin() + decoded_bytes, temp.end() );
    output = temp;
    return true;
}

} // namespace Encoding

namespace Hash {

Data Sha256( const Data& input )
{
    sha256_ctx ctx;
    nettle_sha256_init( &ctx );
    nettle_sha256_update( &ctx, input.size(), input.data() );
    Data output( SHA256_DIGEST_SIZE  );
    nettle_sha256_digest( &ctx, SHA256_DIGEST_SIZE, output.data() );
    return output;
}

Data Md5( const Data& input )
{
    md5_ctx ctx;
    nettle_md5_init( &ctx );
    nettle_md5_update( &ctx, input.size(), input.data() );
    Data output( MD5_DIGEST_SIZE );
    nettle_md5_digest( &ctx, MD5_DIGEST_SIZE, output.data() );
    return output;
}

} // namespace Hash

/*
 * Adds PKCS#7 padding to the data
 */
void AddPadding( Data& target, std::size_t block_size )
{
    auto pad = block_size - target.size() % block_size;
    target.resize( target.size() + pad, pad );
}

/*
 * Encrypts using the AES256 algorthim
 * PRE: Key is 256-bit (32 octects) long
 * POST: output contains the encrypted data
 * Notes: plain_text will be padded using the PKCS#7 algorthm,
 *        if the decoding fails, output is unchanged
 * Returns true on success
 */
bool Aes256Encrypt( Data plain_text, const Data& key, Data& output )
{
    if ( key.size() != AES256_KEY_SIZE )
    {
        return false;
    }
    aes256_ctx ctx;
    nettle_aes256_set_encrypt_key( &ctx, key.data() );
    AddPadding( plain_text, AES_BLOCK_SIZE );
    output.resize( plain_text.size(), 0 );
    nettle_aes256_encrypt( &ctx, plain_text.size(),
        output.data(), plain_text.data() );
    nettle_aes256_decrypt( &ctx, plain_text.size(),
        plain_text.data(), output.data() );
    return true;
}

/*
 * Encrypts using the AES256 algorthim
 * PRE: Key is 256-bit (32 octects) long,
 *      cypher_text.size() is an integer multiple of the AES block size
 * POST: output contains the decrypted data
 * Note: If the decoding fails, output is unchanged
 * Returns true on success
 */
bool Aes256Decrypt( Data cypher_text, const Data& key, Data& output )
{
    if ( key.size() != AES256_KEY_SIZE || cypher_text.size() % AES_BLOCK_SIZE )
    {
        return true;
    }
    aes256_ctx ctx;
    nettle_aes256_set_decrypt_key( &ctx, key.data() );
    output.resize( cypher_text.size(), 0 );
    nettle_aes256_decrypt( &ctx, cypher_text.size(),
        output.data(), cypher_text.data() );
    return true;
}

} // namespace Crypto
<commit_msg>Don't include nettle/version.h<commit_after>/*
===========================================================================
Daemon BSD Source Code
Copyright (c) 2015, Daemon Developers
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Daemon developers nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===========================================================================
*/

#include "common/System.h"
#include "common/String.h"
#include "Crypto.h"
#include <nettle/aes.h>
#include <nettle/base64.h>
#include <nettle/md5.h>
#include <nettle/sha2.h>

// Compatibility with old nettle versions
#if !defined(AES256_KEY_SIZE)

#define AES256_KEY_SIZE 32

typedef aes_ctx compat_aes256_ctx;

static void nettle_compat_aes256_set_encrypt_key(compat_aes256_ctx *ctx, const uint8_t *key)
{
	nettle_aes_set_encrypt_key(ctx, AES256_KEY_SIZE, key);
}

static void nettle_compat_aes256_set_decrypt_key(compat_aes256_ctx *ctx, const uint8_t *key)
{
	nettle_aes_set_decrypt_key(ctx, AES256_KEY_SIZE, key);
}

static void nettle_compat_aes256_encrypt(const compat_aes256_ctx *ctx,
						   size_t length, uint8_t *dst,
						   const uint8_t *src)
{
	nettle_aes_encrypt(ctx, length, dst, src);
}

static void nettle_compat_aes256_decrypt(const compat_aes256_ctx *ctx,
						   size_t length, uint8_t *dst,
						   const uint8_t *src)
{
	nettle_aes_decrypt(ctx, length, dst, src);
}

static int nettle_compat_base64_decode_update(base64_decode_ctx *ctx,
		     size_t *dst_length,
		     uint8_t *dst,
		     size_t src_length,
		     const uint8_t *src)
{
	unsigned dst_length_uns = *dst_length;
	nettle_base64_decode_update(ctx, &dst_length_uns, dst, src_length, src);
}

#undef aes256_set_encrypt_key
#define nettle_aes256_set_encrypt_key nettle_compat_aes256_set_encrypt_key
#define nettle_aes256_set_decrypt_key nettle_compat_aes256_set_decrypt_key
#define nettle_aes256_invert_key      nettle_compat_aes256_invert_key
#define nettle_aes256_encrypt         nettle_compat_aes256_encrypt
#define nettle_aes256_decrypt         nettle_compat_aes256_decrypt
#define aes256_ctx compat_aes256_ctx
#define nettle_base64_decode_update nettle_compat_base64_decode_update

#endif // NETTLE_VERSION_MAJOR < 3

namespace Crypto {

Data RandomData( std::size_t bytes )
{
    Data data( bytes );
    Sys::GenRandomBytes(data.data(), data.size());
    return data;
}

namespace Encoding {

/*
 * Translates binary data into a hexadecimal string
 */
Data HexEncode( const Data& input )
{
    std::ostringstream stream;
    stream.setf(std::ios::hex, std::ios::basefield);
    stream.fill('0');
    for ( auto ch : input )
    {
        stream.width(2);
        stream << int( ch );
    }
    auto string = stream.str();
    return Data(string.begin(), string.end());
}

/*
 * Translates a hexadecimal string into binary data
 * PRE: input is a valid hexadecimal string
 * POST: output contains the decoded string
 * Returns true on success
 * Note: If the decoding fails, output is unchanged
 */
bool HexDecode( const Data& input, Data& output )
{
    if ( input.size() % 2 )
    {
		return false;
    }

    Data mid( input.size() / 2 );

    for ( std::size_t i = 0; i < input.size(); i += 2 )
    {
        if ( !Str::cisxdigit( input[i] ) || !Str::cisxdigit( input[i+1] ) )
        {
            return false;
        }

        mid[ i / 2 ] = ( Str::GetHex( input[i] ) << 4 ) | Str::GetHex( input[i+1] );
    }

    output = mid;
    return true;
}

/*
 * Translates binary data into a base64 encoded string
 */
Data Base64Encode( const Data& input )
{
    base64_encode_ctx ctx;
    nettle_base64_encode_init( &ctx );

    Data output( BASE64_ENCODE_LENGTH( input.size() ) + BASE64_ENCODE_FINAL_LENGTH );
    int encoded_bytes = nettle_base64_encode_update(
        &ctx, output.data(), input.size(), input.data()
    );
    encoded_bytes += nettle_base64_encode_final( &ctx, output.data() + encoded_bytes );
    output.erase( output.begin() + encoded_bytes, output.end() );
    return output;
}

/*
 * Translates a base64 encoded string into binary data
 * PRE: input is a valid Base64 string
 * POST: output contains the decoded string
 * Returns true on success
 * Note: If the decoding fails, output is unchanged
 */
bool Base64Decode( const Data& input, Data& output )
{
    base64_decode_ctx ctx;
    nettle_base64_decode_init( &ctx );

    Data temp( BASE64_DECODE_LENGTH( input.size() ) );
    std::size_t decoded_bytes = 0;
    if ( !nettle_base64_decode_update( &ctx, &decoded_bytes, temp.data(),
                                       input.size(), input.data() ) )
    {
        return false;
    }

    if ( !nettle_base64_decode_final( &ctx ) )
    {
        return false;
    }

    temp.erase( temp.begin() + decoded_bytes, temp.end() );
    output = temp;
    return true;
}

} // namespace Encoding

namespace Hash {

Data Sha256( const Data& input )
{
    sha256_ctx ctx;
    nettle_sha256_init( &ctx );
    nettle_sha256_update( &ctx, input.size(), input.data() );
    Data output( SHA256_DIGEST_SIZE  );
    nettle_sha256_digest( &ctx, SHA256_DIGEST_SIZE, output.data() );
    return output;
}

Data Md5( const Data& input )
{
    md5_ctx ctx;
    nettle_md5_init( &ctx );
    nettle_md5_update( &ctx, input.size(), input.data() );
    Data output( MD5_DIGEST_SIZE );
    nettle_md5_digest( &ctx, MD5_DIGEST_SIZE, output.data() );
    return output;
}

} // namespace Hash

/*
 * Adds PKCS#7 padding to the data
 */
void AddPadding( Data& target, std::size_t block_size )
{
    auto pad = block_size - target.size() % block_size;
    target.resize( target.size() + pad, pad );
}

/*
 * Encrypts using the AES256 algorthim
 * PRE: Key is 256-bit (32 octects) long
 * POST: output contains the encrypted data
 * Notes: plain_text will be padded using the PKCS#7 algorthm,
 *        if the decoding fails, output is unchanged
 * Returns true on success
 */
bool Aes256Encrypt( Data plain_text, const Data& key, Data& output )
{
    if ( key.size() != AES256_KEY_SIZE )
    {
        return false;
    }
    aes256_ctx ctx;
    nettle_aes256_set_encrypt_key( &ctx, key.data() );
    AddPadding( plain_text, AES_BLOCK_SIZE );
    output.resize( plain_text.size(), 0 );
    nettle_aes256_encrypt( &ctx, plain_text.size(),
        output.data(), plain_text.data() );
    nettle_aes256_decrypt( &ctx, plain_text.size(),
        plain_text.data(), output.data() );
    return true;
}

/*
 * Encrypts using the AES256 algorthim
 * PRE: Key is 256-bit (32 octects) long,
 *      cypher_text.size() is an integer multiple of the AES block size
 * POST: output contains the decrypted data
 * Note: If the decoding fails, output is unchanged
 * Returns true on success
 */
bool Aes256Decrypt( Data cypher_text, const Data& key, Data& output )
{
    if ( key.size() != AES256_KEY_SIZE || cypher_text.size() % AES_BLOCK_SIZE )
    {
        return true;
    }
    aes256_ctx ctx;
    nettle_aes256_set_decrypt_key( &ctx, key.data() );
    output.resize( cypher_text.size(), 0 );
    nettle_aes256_decrypt( &ctx, cypher_text.size(),
        output.data(), cypher_text.data() );
    return true;
}

} // namespace Crypto
<|endoftext|>


<commit_before>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstring>
#include <utility>
#include <algorithm>
#include <functional>
#include <type_traits>
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<Payload &, Type &>>>
auto to_function_pointer(Ret(*)(Type &, Args...), Payload &) -> Ret(*)(Args...);

template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<Payload *, Type *>>>
auto to_function_pointer(Ret(*)(Type *, Args...), Payload *) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...), const Class &) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class &) -> Ret(*)(Args...);

template<typename Class, typename Type>
auto to_function_pointer(Type Class:: *, const Class &) -> Type(*)();

template<typename>
struct function_extent;

template<typename Ret, typename... Args>
struct function_extent<Ret(*)(Args...)> {
    static constexpr auto value = sizeof...(Args);
};

template<typename Func>
constexpr auto function_extent_v = function_extent<Func>::value;

}

/**
 * Internal details not to be documented.
 * @endcond TURN_OFF_DOXYGEN
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as general purpose invoker with no memory overhead for
 * free functions (with or without payload) and members provided along with an
 * instance on which to invoke them.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    using proto_fn_type = Ret(const void *, std::tuple<Args &&...>);

    template<auto Function, std::size_t... Index>
    void connect(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Function), std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = nullptr;

        fn = [](const void *, std::tuple<Args &&...> args) -> Ret {
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    void connect(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = &value_or_instance;

        fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = value_or_instance;

        fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

public:
    /*! @brief Function type of the delegate. */
    using function_type = Ret(Args...);

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function to it.
     * @tparam Function A valid free function pointer.
     */
    template<auto Function>
    delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Function>();
    }

    /**
     * @brief Constructs a delegate and connects a member for a given instance
     * or a free function with payload.
     * @tparam Candidate Member or free function to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Connects a free function to a delegate.
     * @tparam Function A valid free function pointer.
     */
    template<auto Function>
    void connect() ENTT_NOEXCEPT {
        constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Function)>()))>;
        connect<Function>(std::make_index_sequence<extent>{});
    }

    /**
     * @brief Connects a member function for a given instance or a free function
     * with payload to a delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one  of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Member or free function to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &&value_or_instance) ENTT_NOEXCEPT {
        constexpr auto extent = internal::function_extent_v<decltype(internal::to_function_pointer(std::declval<decltype(Candidate)>(), std::forward<Type>(value_or_instance)))>;
        connect<Candidate>(std::forward<Type>(value_or_instance), std::make_index_sequence<extent>{});
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.

     * An assertion will abort the execution at runtime in debug mode if the
     * delegate has not yet been set.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return fn;
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    proto_fn_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 *
 * It allows to deduce the function type of the delegate directly from a
 * function provided to the constructor.
 *
 * @tparam Function A valid free function pointer.
 */
template<auto Function>
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Function))>>;

/**
 * @brief Deduction guide.
 *
 * It allows to deduce the function type of the delegate directly from a member
 * or a free function with payload provided to the constructor.
 *
 * @param value_or_instance A valid reference that fits the purpose.
 * @tparam Candidate Member or free function to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Candidate, std::forward<Type>(value_or_instance)))>>;

}

#endif // ENTT_SIGNAL_DELEGATE_HPP
<commit_msg>minor changes<commit_after>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstring>
#include <utility>
#include <algorithm>
#include <functional>
#include <type_traits>
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload &, const Type &>>>
auto to_function_pointer(Ret(*)(Type &, Args...), const Payload &) -> Ret(*)(Args...);

template<typename Ret, typename... Args, typename Type, typename Payload, typename = std::enable_if_t<std::is_convertible_v<const Payload *, const Type *>>>
auto to_function_pointer(Ret(*)(Type *, Args...), const Payload *) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...), const Class &) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...) const, const Class &) -> Ret(*)(Args...);

template<typename Class, typename Type>
auto to_function_pointer(Type Class:: *, const Class &) -> Type(*)();

template<typename... Type>
using to_function_pointer_t = decltype(internal::to_function_pointer(std::declval<Type>()...));

template<typename>
struct function_extent;

template<typename Ret, typename... Args>
struct function_extent<Ret(*)(Args...)> {
    static constexpr auto value = sizeof...(Args);
};

template<typename Func>
constexpr auto function_extent_v = function_extent<Func>::value;

}

/**
 * Internal details not to be documented.
 * @endcond TURN_OFF_DOXYGEN
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as general purpose invoker with no memory overhead for
 * free functions (with or without payload) and members provided along with an
 * instance on which to invoke them.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    using proto_fn_type = Ret(const void *, std::tuple<Args &&...>);

    template<auto Function, std::size_t... Index>
    void connect(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Function), std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = nullptr;

        fn = [](const void *, std::tuple<Args &&...> args) -> Ret {
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    void connect(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = &value_or_instance;

        fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
        data = value_or_instance;

        fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            // Ret(...) makes void(...) eat the return values to avoid errors
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
        };
    }

public:
    /*! @brief Function type of the delegate. */
    using function_type = Ret(Args...);

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function to it.
     * @tparam Function A valid free function pointer.
     */
    template<auto Function>
    delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Function>();
    }

    /**
     * @brief Constructs a delegate and connects a member for a given instance
     * or a free function with payload.
     * @tparam Candidate Member or free function to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Connects a free function to a delegate.
     * @tparam Function A valid free function pointer.
     */
    template<auto Function>
    void connect() ENTT_NOEXCEPT {
        constexpr auto extent = internal::function_extent_v<internal::to_function_pointer_t<decltype(Function)>>;
        connect<Function>(std::make_index_sequence<extent>{});
    }

    /**
     * @brief Connects a member function for a given instance or a free function
     * with payload to a delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one  of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Member or free function to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &&value_or_instance) ENTT_NOEXCEPT {
        constexpr auto extent = internal::function_extent_v<internal::to_function_pointer_t<decltype(Candidate), Type>>;
        connect<Candidate>(std::forward<Type>(std::forward<Type>(value_or_instance)), std::make_index_sequence<extent>{});
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.

     * An assertion will abort the execution at runtime in debug mode if the
     * delegate has not yet been set.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return fn;
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    proto_fn_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 *
 * It allows to deduce the function type of the delegate directly from a
 * function provided to the constructor.
 *
 * @tparam Function A valid free function pointer.
 */
template<auto Function>
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Function)>>>;

/**
 * @brief Deduction guide.
 *
 * It allows to deduce the function type of the delegate directly from a member
 * or a free function with payload provided to the constructor.
 *
 * @param value_or_instance A valid reference that fits the purpose.
 * @tparam Candidate Member or free function to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::to_function_pointer_t<decltype(Candidate), Type>>>;

}

#endif // ENTT_SIGNAL_DELEGATE_HPP
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media/desktop_media_picker_model.h"

#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"

using testing::_;
using testing::AtMost;
using testing::DoAll;

namespace {

class MockObserver : public DesktopMediaPickerModel::Observer {
 public:
  MOCK_METHOD1(OnSourceAdded, void(int index));
  MOCK_METHOD1(OnSourceRemoved, void(int index));
  MOCK_METHOD1(OnSourceNameChanged, void(int index));
  MOCK_METHOD1(OnSourceThumbnailChanged, void(int index));
};

class FakeScreenCapturer : public webrtc::ScreenCapturer {
 public:
  FakeScreenCapturer() {}
  virtual ~FakeScreenCapturer() {}

  // webrtc::ScreenCapturer implementation.
  virtual void Start(Callback* callback) OVERRIDE {
    callback_ = callback;
  }

  virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
    DCHECK(callback_);
    webrtc::DesktopFrame* frame =
        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
    memset(frame->data(), 0, frame->stride() * frame->size().height());
    callback_->OnCaptureCompleted(frame);
  }

  virtual void SetMouseShapeObserver(
      MouseShapeObserver* mouse_shape_observer) OVERRIDE {
    NOTIMPLEMENTED();
  }

 protected:
  Callback* callback_;

  DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer);
};

class FakeWindowCapturer : public webrtc::WindowCapturer {
 public:
  FakeWindowCapturer()
      : callback_(NULL) {
  }
  virtual ~FakeWindowCapturer() {
    STLDeleteContainerPairSecondPointers(frames_.begin(), frames_.end());
  }

  void SetWindowList(const WindowList& list) {
    base::AutoLock lock(window_list_lock_);
    window_list_ = list;
  }

  void SetNextFrame(WindowId window_id,
                    scoped_ptr<webrtc::DesktopFrame> frame) {
      frames_[window_id] = frame.release();
  }

  // webrtc::WindowCapturer implementation.
  virtual void Start(Callback* callback) OVERRIDE {
    callback_ = callback;
  }

  virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
    DCHECK(callback_);

    webrtc::DesktopFrame* frame;
    std::map<WindowId, webrtc::DesktopFrame*>::iterator it =
        frames_.find(selected_window_id_);
    if (it == frames_.end()) {
      frame = new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
      memset(frame->data(), 0, frame->stride() * frame->size().height());
    } else {
      frame = it->second;
      frames_.erase(it);
    }
    callback_->OnCaptureCompleted(frame);
  }

  virtual bool GetWindowList(WindowList* windows) OVERRIDE {
    base::AutoLock lock(window_list_lock_);
    *windows = window_list_;
    return true;
  }

  virtual bool SelectWindow(WindowId id) OVERRIDE {
    selected_window_id_ = id;
    return true;
  }

 private:
  Callback* callback_;
  WindowList window_list_;
  base::Lock window_list_lock_;

  WindowId selected_window_id_;

  // Frames to be captured per window.
  std::map<WindowId, webrtc::DesktopFrame*> frames_;

  DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
};

class DesktopMediaPickerModelTest : public testing::Test {
 public:
  DesktopMediaPickerModelTest()
      : ui_thread_(content::BrowserThread::UI,
                   &message_loop_) {
    window_capturer_ = new FakeWindowCapturer();
    // Set update period to reduce the time it takes to run tests.
    model_.SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
  }

  void SetDefaultCapturers() {
    model_.SetCapturers(
        scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
        scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
  }

 protected:
  // Must be listed before |model_|, so it's destroyed last.
  MockObserver observer_;

  // Owned by |model_|;
  FakeWindowCapturer* window_capturer_;

  DesktopMediaPickerModel model_;

  base::MessageLoop message_loop_;
  content::TestBrowserThread ui_thread_;

  DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerModelTest);
};

ACTION_P2(CheckListSize, model, expected_list_size) {
  EXPECT_EQ(expected_list_size, model->source_count());
}

ACTION_P(QuitMessageLoop, message_loop) {
  message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}

TEST_F(DesktopMediaPickerModelTest, InitialSourceList) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_SCREEN_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(0).id.id, 0);
  EXPECT_EQ(model_.source(1).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(1).id.id, 0);
  EXPECT_EQ(model_.source(1).name, UTF8ToUTF16(window.title));
}

TEST_F(DesktopMediaPickerModelTest, WindowsOnly) {
  model_.SetCapturers(
      scoped_ptr<webrtc::ScreenCapturer>(),
      scoped_ptr<webrtc::WindowCapturer>(window_capturer_));

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
}

TEST_F(DesktopMediaPickerModelTest, ScreenOnly) {
  model_.SetCapturers(
      scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
      scoped_ptr<webrtc::WindowCapturer>());

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_SCREEN_VIDEO_CAPTURE);
}

TEST_F(DesktopMediaPickerModelTest, AddWindow) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 1;
  window.title = "Test window 1";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceAdded(1))
    .WillOnce(DoAll(CheckListSize(&model_, 3),
                    QuitMessageLoop(&message_loop_)));

  window.id = 0;
  window.title = "Test window 0";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  message_loop_.Run();

  EXPECT_EQ(model_.source(1).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(1).id.id, 0);
}

TEST_F(DesktopMediaPickerModelTest, RemoveWindow) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window 0";
  list.push_back(window);
  window.id = 1;
  window.title = "Test window 1";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceAdded(2))
      .WillOnce(CheckListSize(&model_, 3));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceRemoved(1))
    .WillOnce(DoAll(CheckListSize(&model_, 2),
                    QuitMessageLoop(&message_loop_)));

  list.erase(list.begin());
  window_capturer_->SetWindowList(list);

  message_loop_.Run();
}

TEST_F(DesktopMediaPickerModelTest, UpdateTitle) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceNameChanged(1))
    .WillOnce(QuitMessageLoop(&message_loop_));

  const std::string kTestTitle = "New Title";

  list[0].title = kTestTitle;
  window_capturer_->SetWindowList(list);

  message_loop_.Run();

  EXPECT_EQ(model_.source(1).name, base::UTF8ToUTF16(kTestTitle));
}

TEST_F(DesktopMediaPickerModelTest, UpdateThumbnail) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window 1";
  list.push_back(window);
  window.id = 1;
  window.title = "Test window 2";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceAdded(2))
      .WillOnce(CheckListSize(&model_, 3));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    .WillOnce(QuitMessageLoop(&message_loop_));

  // Update frame for the window and verify that we get notification about it.
  scoped_ptr<webrtc::DesktopFrame> frame(
      new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
  memset(frame->data(), 1, frame->stride() * frame->size().height());
  window_capturer_->SetNextFrame(0, frame.Pass());

  message_loop_.Run();
}

}  // namespace
<commit_msg>Fix memory leak in DesktopMediaPickerModelTest.ScreenOnly<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media/desktop_media_picker_model.h"

#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"

using testing::_;
using testing::AtMost;
using testing::DoAll;

namespace {

class MockObserver : public DesktopMediaPickerModel::Observer {
 public:
  MOCK_METHOD1(OnSourceAdded, void(int index));
  MOCK_METHOD1(OnSourceRemoved, void(int index));
  MOCK_METHOD1(OnSourceNameChanged, void(int index));
  MOCK_METHOD1(OnSourceThumbnailChanged, void(int index));
};

class FakeScreenCapturer : public webrtc::ScreenCapturer {
 public:
  FakeScreenCapturer() {}
  virtual ~FakeScreenCapturer() {}

  // webrtc::ScreenCapturer implementation.
  virtual void Start(Callback* callback) OVERRIDE {
    callback_ = callback;
  }

  virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
    DCHECK(callback_);
    webrtc::DesktopFrame* frame =
        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
    memset(frame->data(), 0, frame->stride() * frame->size().height());
    callback_->OnCaptureCompleted(frame);
  }

  virtual void SetMouseShapeObserver(
      MouseShapeObserver* mouse_shape_observer) OVERRIDE {
    NOTIMPLEMENTED();
  }

 protected:
  Callback* callback_;

  DISALLOW_COPY_AND_ASSIGN(FakeScreenCapturer);
};

class FakeWindowCapturer : public webrtc::WindowCapturer {
 public:
  FakeWindowCapturer()
      : callback_(NULL) {
  }
  virtual ~FakeWindowCapturer() {
    STLDeleteContainerPairSecondPointers(frames_.begin(), frames_.end());
  }

  void SetWindowList(const WindowList& list) {
    base::AutoLock lock(window_list_lock_);
    window_list_ = list;
  }

  void SetNextFrame(WindowId window_id,
                    scoped_ptr<webrtc::DesktopFrame> frame) {
      frames_[window_id] = frame.release();
  }

  // webrtc::WindowCapturer implementation.
  virtual void Start(Callback* callback) OVERRIDE {
    callback_ = callback;
  }

  virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
    DCHECK(callback_);

    webrtc::DesktopFrame* frame;
    std::map<WindowId, webrtc::DesktopFrame*>::iterator it =
        frames_.find(selected_window_id_);
    if (it == frames_.end()) {
      frame = new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
      memset(frame->data(), 0, frame->stride() * frame->size().height());
    } else {
      frame = it->second;
      frames_.erase(it);
    }
    callback_->OnCaptureCompleted(frame);
  }

  virtual bool GetWindowList(WindowList* windows) OVERRIDE {
    base::AutoLock lock(window_list_lock_);
    *windows = window_list_;
    return true;
  }

  virtual bool SelectWindow(WindowId id) OVERRIDE {
    selected_window_id_ = id;
    return true;
  }

 private:
  Callback* callback_;
  WindowList window_list_;
  base::Lock window_list_lock_;

  WindowId selected_window_id_;

  // Frames to be captured per window.
  std::map<WindowId, webrtc::DesktopFrame*> frames_;

  DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
};

class DesktopMediaPickerModelTest : public testing::Test {
 public:
  DesktopMediaPickerModelTest()
      : window_capturer_(NULL),
        ui_thread_(content::BrowserThread::UI,
                   &message_loop_) {
    // Set update period to reduce the time it takes to run tests.
    model_.SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
  }

  void SetDefaultCapturers() {
    window_capturer_ = new FakeWindowCapturer();
    model_.SetCapturers(
        scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
        scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
  }

 protected:
  // Must be listed before |model_|, so it's destroyed last.
  MockObserver observer_;

  // Owned by |model_|;
  FakeWindowCapturer* window_capturer_;

  DesktopMediaPickerModel model_;

  base::MessageLoop message_loop_;
  content::TestBrowserThread ui_thread_;

  DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerModelTest);
};

ACTION_P2(CheckListSize, model, expected_list_size) {
  EXPECT_EQ(expected_list_size, model->source_count());
}

ACTION_P(QuitMessageLoop, message_loop) {
  message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
}

TEST_F(DesktopMediaPickerModelTest, InitialSourceList) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_SCREEN_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(0).id.id, 0);
  EXPECT_EQ(model_.source(1).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(1).id.id, 0);
  EXPECT_EQ(model_.source(1).name, UTF8ToUTF16(window.title));
}

TEST_F(DesktopMediaPickerModelTest, WindowsOnly) {
  window_capturer_ = new FakeWindowCapturer();
  model_.SetCapturers(
      scoped_ptr<webrtc::ScreenCapturer>(),
      scoped_ptr<webrtc::WindowCapturer>(window_capturer_));

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
}

TEST_F(DesktopMediaPickerModelTest, ScreenOnly) {
  model_.SetCapturers(
      scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
      scoped_ptr<webrtc::WindowCapturer>());

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  EXPECT_EQ(model_.source(0).id.type, content::MEDIA_SCREEN_VIDEO_CAPTURE);
}

TEST_F(DesktopMediaPickerModelTest, AddWindow) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 1;
  window.title = "Test window 1";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceAdded(1))
    .WillOnce(DoAll(CheckListSize(&model_, 3),
                    QuitMessageLoop(&message_loop_)));

  window.id = 0;
  window.title = "Test window 0";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  message_loop_.Run();

  EXPECT_EQ(model_.source(1).id.type, content::MEDIA_WINDOW_VIDEO_CAPTURE);
  EXPECT_EQ(model_.source(1).id.id, 0);
}

TEST_F(DesktopMediaPickerModelTest, RemoveWindow) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window 0";
  list.push_back(window);
  window.id = 1;
  window.title = "Test window 1";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceAdded(2))
      .WillOnce(CheckListSize(&model_, 3));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceRemoved(1))
    .WillOnce(DoAll(CheckListSize(&model_, 2),
                    QuitMessageLoop(&message_loop_)));

  list.erase(list.begin());
  window_capturer_->SetWindowList(list);

  message_loop_.Run();
}

TEST_F(DesktopMediaPickerModelTest, UpdateTitle) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceNameChanged(1))
    .WillOnce(QuitMessageLoop(&message_loop_));

  const std::string kTestTitle = "New Title";

  list[0].title = kTestTitle;
  window_capturer_->SetWindowList(list);

  message_loop_.Run();

  EXPECT_EQ(model_.source(1).name, base::UTF8ToUTF16(kTestTitle));
}

TEST_F(DesktopMediaPickerModelTest, UpdateThumbnail) {
  SetDefaultCapturers();

  webrtc::WindowCapturer::WindowList list;
  webrtc::WindowCapturer::Window window;
  window.id = 0;
  window.title = "Test window 1";
  list.push_back(window);
  window.id = 1;
  window.title = "Test window 2";
  list.push_back(window);
  window_capturer_->SetWindowList(list);

  {
    testing::InSequence dummy;
    EXPECT_CALL(observer_, OnSourceAdded(0))
      .WillOnce(CheckListSize(&model_, 1));
    EXPECT_CALL(observer_, OnSourceAdded(1))
      .WillOnce(CheckListSize(&model_, 2));
    EXPECT_CALL(observer_, OnSourceAdded(2))
      .WillOnce(CheckListSize(&model_, 3));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
    EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
      .WillOnce(QuitMessageLoop(&message_loop_));
  }
  model_.StartUpdating(&observer_);

  message_loop_.Run();

  testing::Mock::VerifyAndClearExpectations(&observer_);

  EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
    .WillOnce(QuitMessageLoop(&message_loop_));

  // Update frame for the window and verify that we get notification about it.
  scoped_ptr<webrtc::DesktopFrame> frame(
      new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
  memset(frame->data(), 1, frame->stride() * frame->size().height());
  window_capturer_->SetNextFrame(0, frame.Pass());

  message_loop_.Run();
}

}  // namespace
<|endoftext|>


<commit_before>#include <glog/logging.h>
#include <util.h>
#include <mailer_pool.h>

using namespace std::placeholders;

namespace {

struct mailer_extra {
  const std::string server;
  const std::string from;
  const std::vector<std::string> to;
};

const std::string k_smtp_url = "smtp://localhost";

typedef std::pair<std::vector<char>, size_t> payload_t;

size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{

  if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) {
    return 0;
  }

  auto payload_data = static_cast<payload_t*>(userp);

  size_t copied = payload_data->second;
  size_t left = payload_data->first.size() - copied;
  size_t to_copy = std::min(size * nmemb, left);

  if (to_copy > 0) {

    memcpy(ptr, static_cast<void*>(&payload_data->first[copied]), to_copy);
    payload_data->second += to_copy;

    return to_copy;

  } else {
    return 0;
  }

}

std::vector<char> payload_text(const mailer_extra extra, const Event & e) {

  std::string to = "unknown";

  if (!extra.to.empty()) {
    to = extra.to[0];
  }

  std::string subject = e.host() + " " + e.service() + " is " + e.state()
                        + metric_to_string(e);

  std::string payload = "To: " + to + "\r\n" +
                        "From: " + extra.from + "\r\n" +
                        "Subject: " + subject + "\r\n" +
                        "\r\n" +
                        event_to_json(e);

  return std::vector<char>(payload.begin(), payload.end());
}

}

mailer_pool::mailer_pool(const size_t thread_num)
  :
  curl_pool_(
      thread_num,
      std::bind(&mailer_pool::curl_event, this, _1, _2, _3)
  )
{
}

void mailer_pool::push_event(const std::string server, const std::string from,
                             const std::vector<std::string> to,
                             const Event & event)
{
  VLOG(3) << "push_event()  server: " << server << " from: " << from;

  mailer_extra extra = {server, from, to};
  curl_pool_.push_event(event, extra);

}

void mailer_pool::curl_event(const queued_event_t queued_event,
                             const std::shared_ptr<CURL> easy,
                             std::function<void()> & clean_fn)
{

  const auto extra = boost::any_cast<mailer_extra>(queued_event.extra);
  const auto & e = queued_event.event;

	std::shared_ptr<std::string> server(new std::string(extra.server));
	std::shared_ptr<std::string> from(new std::string(extra.from));

  struct curl_slist *recipients = NULL;
  for (const auto & to : extra.to) {
    recipients = curl_slist_append(recipients, to.c_str());
  }

  auto payload = std::make_shared<payload_t>(
                                      payload_t({payload_text(extra, e), 0}));

  curl_easy_setopt(easy.get(), CURLOPT_URL, k_smtp_url.c_str());
  curl_easy_setopt(easy.get(), CURLOPT_MAIL_FROM, from->c_str());
  curl_easy_setopt(easy.get(), CURLOPT_MAIL_RCPT, recipients);
  curl_easy_setopt(easy.get(), CURLOPT_UPLOAD, 1L);
  curl_easy_setopt(easy.get(), CURLOPT_READFUNCTION, payload_source);
  curl_easy_setopt(easy.get(), CURLOPT_READDATA, payload.get());

  clean_fn = [=]()
  {
    UNUSED_VAR(server);
    UNUSED_VAR(from);
    UNUSED_VAR(payload);
  };

}
<commit_msg>Free recipients list in mailer_pool<commit_after>#include <glog/logging.h>
#include <util.h>
#include <mailer_pool.h>

using namespace std::placeholders;

namespace {

struct mailer_extra {
  const std::string server;
  const std::string from;
  const std::vector<std::string> to;
};

const std::string k_smtp_url = "smtp://localhost";

typedef std::pair<std::vector<char>, size_t> payload_t;

size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{

  if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) {
    return 0;
  }

  auto payload_data = static_cast<payload_t*>(userp);

  size_t copied = payload_data->second;
  size_t left = payload_data->first.size() - copied;
  size_t to_copy = std::min(size * nmemb, left);

  if (to_copy > 0) {

    memcpy(ptr, static_cast<void*>(&payload_data->first[copied]), to_copy);
    payload_data->second += to_copy;

    return to_copy;

  } else {
    return 0;
  }

}

std::vector<char> payload_text(const mailer_extra extra, const Event & e) {

  std::string to = "unknown";

  if (!extra.to.empty()) {
    to = extra.to[0];
  }

  std::string subject = e.host() + " " + e.service() + " is " + e.state()
                        + metric_to_string(e);

  std::string payload = "To: " + to + "\r\n" +
                        "From: " + extra.from + "\r\n" +
                        "Subject: " + subject + "\r\n" +
                        "\r\n" +
                        event_to_json(e);

  return std::vector<char>(payload.begin(), payload.end());
}

}

mailer_pool::mailer_pool(const size_t thread_num)
  :
  curl_pool_(
      thread_num,
      std::bind(&mailer_pool::curl_event, this, _1, _2, _3)
  )
{
}

void mailer_pool::push_event(const std::string server, const std::string from,
                             const std::vector<std::string> to,
                             const Event & event)
{
  VLOG(3) << "push_event()  server: " << server << " from: " << from;

  mailer_extra extra = {server, from, to};
  curl_pool_.push_event(event, extra);

}

void mailer_pool::curl_event(const queued_event_t queued_event,
                             const std::shared_ptr<CURL> easy,
                             std::function<void()> & clean_fn)
{

  const auto extra = boost::any_cast<mailer_extra>(queued_event.extra);
  const auto & e = queued_event.event;

	std::shared_ptr<std::string> server(new std::string(extra.server));
	std::shared_ptr<std::string> from(new std::string(extra.from));

  struct curl_slist *recipients = NULL;
  for (const auto & to : extra.to) {
    recipients = curl_slist_append(recipients, to.c_str());
  }

  auto payload = std::make_shared<payload_t>(
                                      payload_t({payload_text(extra, e), 0}));

  curl_easy_setopt(easy.get(), CURLOPT_URL, k_smtp_url.c_str());
  curl_easy_setopt(easy.get(), CURLOPT_MAIL_FROM, from->c_str());
  curl_easy_setopt(easy.get(), CURLOPT_MAIL_RCPT, recipients);
  curl_easy_setopt(easy.get(), CURLOPT_UPLOAD, 1L);
  curl_easy_setopt(easy.get(), CURLOPT_READFUNCTION, payload_source);
  curl_easy_setopt(easy.get(), CURLOPT_READDATA, payload.get());

  clean_fn = [=]()
  {
    UNUSED_VAR(server);
    UNUSED_VAR(from);
    UNUSED_VAR(payload);
    if (recipients) {
      curl_slist_free_all(recipients);
    }
  };

}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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.
 *
 ************************************************************************/

#ifndef _LAYOUT_POST_HXX
#define _LAYOUT_POST_HXX

#if ENABLE_LAYOUT

/* Allow re-inclusion for cxx file. */
#undef _LAYOUT_PRE_HXX

#undef AdvancedButton
#undef ApplyButton
#undef Box
#undef Button
#undef CancelButton
#undef CheckBox
#undef ComboBox
#undef Container
#undef Control
#undef Dialog
#undef Edit
#undef ErrorBox
#undef FixedImage
#undef FixedInfo
#undef FixedLine
#undef FixedText
#undef HBox
#undef HelpButton
#undef IgnoreButton
#undef ImageButton
#undef InfoBox
#undef ListBox
#undef MessBox
#undef MessageBox
#undef MetricField
#undef MetricFormatter
#undef MoreButton
#undef MultiLineEdit
#undef MultiListBox
#undef NoButton
#undef NumericField
#undef NumericFormatter
#undef OKButton
#undef Plugin
#undef ProgressBar
#undef PushButton
#undef QueryBox
#undef RadioButton
#undef ResetButton
#undef RetryButton
#undef SfxTabPage
#undef SfxTabDialog
#undef SpinField
#undef TabDialog
#undef TabControl
#undef TabPage
#undef Table
#undef VBox
#undef WarningBox
#undef YesButton

#undef SvxFontListBox
#undef SvxLanguageBox

#undef ModalDialog
#undef ModelessDialog
#undef ScExpandedFixedText
#undef SfxDialog
#undef SfxModalDialog
#undef SfxModelessDialog

#undef Window

#endif /* ENABLE_LAYOUT */

#endif /* _LAYOUT_POST_HXX */

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>add matching undefs<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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.
 *
 ************************************************************************/

#ifndef _LAYOUT_POST_HXX
#define _LAYOUT_POST_HXX

#if ENABLE_LAYOUT

/* Allow re-inclusion for cxx file. */
#undef _LAYOUT_PRE_HXX

#undef AdvancedButton
#undef ApplyButton
#undef Box
#undef Button
#undef CancelButton
#undef CheckBox
#undef ComboBox
#undef Container
#undef Control
#undef Dialog
#undef Edit
#undef ErrorBox
#undef FixedImage
#undef FixedInfo
#undef FixedLine
#undef FixedText
#undef HBox
#undef HelpButton
#undef IgnoreButton
#undef ImageButton
#undef InfoBox
#undef ListBox
#undef MessBox
#undef MessageBox
#undef MetricField
#undef MetricFormatter
#undef MoreButton
#undef MultiLineEdit
#undef MultiListBox
#undef NoButton
#undef NumericField
#undef NumericFormatter
#undef OKButton
#undef Plugin
#undef ProgressBar
#undef PushButton
#undef QueryBox
#undef RadioButton
#undef ResetButton
#undef RetryButton
#undef SfxTabPage
#undef SfxTabDialog
#undef SfxTabPage
#undef SvxFontListBox
#undef SvxLanguageBox
#undef SpinField
#undef TabDialog
#undef TabControl
#undef TabPage
#undef Table
#undef VBox
#undef WarningBox
#undef YesButton

#undef SvxFontListBox
#undef SvxLanguageBox

#undef ModalDialog
#undef ModelessDialog
#undef ScExpandedFixedText
#undef SfxDialog
#undef SfxModalDialog
#undef SfxModelessDialog

#undef Window

#endif /* ENABLE_LAYOUT */

#endif /* _LAYOUT_POST_HXX */

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include<stdio.h>
#include<stdlib.h>
#include<limits.h>//in gcc
#include<errno.h>//in gcc
#ifndef __cplusplus
#define nullptr NULL
#endif

int get_integer_num(const int max, const int min){
	//@\FW͂𐔎ɕϊB
	//F߂l̍ől,߂l̍ŏl
	//߂lF͂AG[-1,EOF̂ƂEOF
	char s[100];
	char *endptr;
	if (nullptr == fgets(s, 100, stdin)){
		if (feof(stdin)){//G[̌EOF؂蕪
			return EOF;
		}
		return INT_MIN;
	}
	if ('\n' == s[0]) return INT_MIN;
	errno = 0;
	const long t = strtol(s, &endptr, 10);
	if (0 != errno || '\n' != *endptr || t < min || max < t)
		return INT_MIN;
	return (int)t;
}

int getnum_customized_type_int(const int max, const int min){
	if (max < min)   return -1;
	int flag0;
	bool temp_judge;
	do{
		flag0 = get_integer_num(max, min);
		temp_judge = (INT_MIN == flag0);
		if (temp_judge){
			system("cls");
			puts("ē͂ĂB");
		}
	} while (temp_judge);
	return flag0;
}

double getnum(const double max, const double min, double* isError){
	//@\FW͂𐔎ɕϊB
	//F߂l̍ől,߂l̍ŏl
	//߂lF͂AG[-1,EOF̂ƂEOF
	char s[100];
	char *endptr;
	if (nullptr == fgets(s, 100, stdin)){
		if (nullptr != isError) *isError = -1;
		return 0;
	}
	if ('\n' == s[0]){
		if (nullptr != isError) *isError = -1;
		return 0;
	}
	errno = 0;
	const double t = strtod(s, &endptr);
	if (0 != errno || '\n' != *endptr || t < min || max < t)
		if (nullptr != isError) *isError = -1;
	return t;
}

double getnum_customized_type_double(const double max, const double min){
	if (max < min)   return -1;
	double flag0 = 0;
	double return_num;
	bool temp_judge;
	do{
		return_num = getnum(max, min, &flag0);
		temp_judge = (-1 == flag0);
		if (temp_judge){
			//system("cls");
			puts("ē͂ĂB");
		}
	} while (temp_judge);
	return return_num;
}

void common_message(void){
	printf("Cϊc[\n\n");
}

void hPa_to_mmHg(void){
	printf("C(hPa)͂ĂB\n");
	double Pa = getnum_customized_type_double(5000, 0);
	system("cls");
	double calc_mmHg = Pa * 760 / 1013;
	common_message();
	printf("%fhPa%fmmHgłB\n", Pa, calc_mmHg);
}

void mmHg_to_hPa(void){
	printf("C(mmHg)͂ĂB\n");
	double mmHg = getnum_customized_type_double(5000, 0);
	system("cls");
	double calc_Pa = mmHg * 1013 / 760;
	common_message();
	printf("%fmmHg%fPałB\n", mmHg, calc_Pa);
}

void clear_screen(void){
	system("pause");
	system("cls");
}

void roop(void){
	int flag = 0;
	int flag2;
	int end = 0;
	do{
		common_message();
		switch (flag){
		case 0:{
			flag2 = 0;
			printf("PammHgɕϊꍇ͂PAmmHgPaɕϊꍇ͂Q͂EnterL[ĂB\n"
				"Iꍇ͂R͂ĂB\n");
			flag = getnum_customized_type_int(3, 1);
			system("cls");
			break;
		}
		case 1:{
			hPa_to_mmHg();
			flag = 4;
			clear_screen();
			break;
		}
		case 2:{
			mmHg_to_hPa();
			flag = 4;
			clear_screen();
			break;
		}
		case 3:{
			end = 1;
			break;
		}
		case 4:{
			printf("vZ𑱂܂H\n͂cP@cQ\n");
			flag2 = getnum_customized_type_int(2, 1);
			if (flag2 == 1) flag = 0;
			if (flag2 == 2) flag = 3;
			system("cls");
			break;
		}
		default:
			break;
		}
	} while (end == 0);
}

int main(void){
	roop();
	return 0;
}<commit_msg>C++っぽく書き換え。 760mmHg->atm みたいに書けるように<commit_after>#include<iostream>
#include<string>
#include<array>
#include<typeinfo>
#include<cstdio>
#include<cstdlib>
#include<limits.h>//in gcc
#include<errno.h>//in gcc
typedef enum pressure_unit{
	UNKNOWN = 0,
	MMHG,
	HPA,
	ATM,
	BAR
} pressure_unit_t;
typedef struct{
	double pressure;
	pressure_unit_t in_unit;
	pressure_unit_t out_unit;
}input_pressure_data_t;
template <typename T, typename ...Args>
inline std::array<T, sizeof...(Args)> make_array(Args &&...args) {
	return std::array<T, sizeof...(Args)>{ std::forward<Args>(args)... };
}
namespace pressure_units{
	static const auto units = make_array<std::string>("mmHg", "hPa", "atm", "bar");
	class basic_pressure_t
	{
	public:
		basic_pressure_t(double hPa){
			this->hPa = hPa;
		}
		basic_pressure_t(double in_pressure, const pressure_unit_t unit){
			hPa = 0;
			switch (unit)
			{
			case MMHG:
				hPa = in_pressure * 1013.25 / 760;
				break;
			case HPA:
				hPa = in_pressure;
				break;
			case ATM:
				hPa = in_pressure * 1013.25;
				break;
			case BAR:
				hPa = in_pressure * 1000;
				break;
			default:
				throw "unknown units";
				break;
			}
			mmHg = (MMHG != unit) ? hPa * 760 / 1013.25 : in_pressure;
			atm = (ATM != unit) ? hPa / 1013.25 : in_pressure;
			bar = (BAR != unit) ? hPa / 1000 : in_pressure;
		}
		std::string to_string(const pressure_unit_t unit) const{
			std::string re = "";
			switch (unit)
			{
			case MMHG:
				re += std::to_string(mmHg);
				break;
			case HPA:
				re += std::to_string(hPa);
				break;
			case ATM:
				re += std::to_string(atm);
				break;
			case BAR:
				re += std::to_string(bar);
				break;
			default:
				throw "unknown units";
				break;
			}
			re += (UNKNOWN == unit) ? "" : units.at(unit - 1);
			return re;
		}
	private:
		double hPa, mmHg, atm, bar;
	};
}
pressure_unit_t to_pressure_unit(const std::string& in_str, size_t* _Idx = nullptr){
	using namespace pressure_units;
	if (0 == in_str.length()) return UNKNOWN;
	//static const auto units = make_array<std::string>("mmHg", "hPa", "atm", "bar");
	std::string::size_type place = 0, i = 0;
	for (auto& u : units){
		place = in_str.find(u);
		if (0 == place) break;
		++i;
	}
	if (0 != place) return UNKNOWN;
	if (nullptr != _Idx) *_Idx = units.at(i).length();//in_str中のkey(units[i])のすぐ後の要素番号を引数経由で返す
	return static_cast<pressure_unit_t>(i + 1);
}
template <typename T_>
pressure_unit_t ask_unit(T_ pressure){
	using namespace std;
	string in_unit_str;
	in_unit_str.reserve(10);
	pressure_unit_t re;
	do{
		cout << pressure << "の単位を入力してください" << endl;
		cout << "mmHg, hPa, atm, bar" << endl;
		getline(cin, in_unit_str);
		re = to_pressure_unit(in_unit_str);
	} while (UNKNOWN == re);
	return re;
}
void split_into_pressure_data(input_pressure_data_t& data, const std::string& in_str){
	std::string::size_type in_unit_str_at = 0, out_unit_str_at = 0;
	data.pressure = stod(in_str, &in_unit_str_at);//doubleに変換
	const pressure_unit_t in_unit_temp = to_pressure_unit(in_str.substr(in_unit_str_at), &out_unit_str_at);
	data.in_unit = (UNKNOWN == in_unit_temp) ? ask_unit(data.pressure) : in_unit_temp;
	//in_unitでask_unitを呼び出しているならout_unitでも呼ぶ必要がある
	const pressure_unit_t out_unit_temp = (UNKNOWN == in_unit_temp) ? ask_unit("変換後") : to_pressure_unit(in_str.substr(in_unit_str_at + out_unit_str_at + 2));
	data.out_unit = (UNKNOWN == out_unit_temp) ? ask_unit("変換後") : out_unit_temp;
}
void common_message(void){
	printf("気圧変換ツール\n\n");
}
void input(input_pressure_data_t& data){
	using namespace std;
	common_message();
	cout << "気圧を入力してください" << endl;
	string in_str;
	in_str.reserve(15);
	getline(cin, in_str);
	split_into_pressure_data(data, in_str);
}
std::string convert(const input_pressure_data_t& data){
	using namespace pressure_units;
	basic_pressure_t in(data.pressure, data.in_unit);
	return in.to_string(data.out_unit);
}
int main(void){
	input_pressure_data_t data;
	input(data);
	std::cout << convert(data) << std::endl;
	return 0;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <exception>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <variant>

#include "int_parser.h"

namespace {

template <typename T>
T _parse_int(const std::string &num __attribute__((unused)),
             size_t *idx __attribute__((unused)),
             int base __attribute__((unused)))
{
  static_assert(not std::is_same_v<T, T>,
                "BUG: _parse_int not implemented for type");
}

template <>
int64_t _parse_int(const std::string &num, size_t *idx, int base)
{
  return std::stoll(num, idx, base);
}

template <>
uint64_t _parse_int(const std::string &num, size_t *idx, int base)
{
  return std::stoull(num, idx, base);
}

template <typename T>
std::variant<T, std::string> _parse_int(const std::string &num, int base)
{
  // https://en.cppreference.com/w/cpp/language/integer_literal#The_type_of_the_literal
  static auto int_size_re = std::regex("^(u|u?l?l)$", std::regex::icase);
  try
  {
    std::size_t idx;
    T ret = _parse_int<T>(num, &idx, base);

    if (idx != num.size())
    {
      auto trail = num.substr(idx, std::string::npos);
      auto match = std::regex_match(trail, int_size_re);

      if (!match)
        return "Found trailing non-numeric characters";
    }

    return ret;
  }
  catch (const std::exception &ex)
  {
    return ex.what();
  }
}

// integer variant of   10^exp
uint64_t _ten_pow(uint64_t exp)
{
  static const uint64_t v[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
  if (exp > 6)
    return v[6] * _ten_pow(exp - 6);
  return v[exp];
}

// integer variant of scientific notation parsing
template <typename T>
std::variant<T, std::string> _parse_exp(const std::string &coeff,
                                        const std::string &exp)
{
  std::stringstream errmsg;
  auto maybe_coeff = _parse_int<T>(coeff, 10);
  if (auto err = std::get_if<std::string>(&maybe_coeff))
  {
    errmsg << "Coefficient part of scientific literal is not a valid number: "
           << coeff << ": " << err;
    return errmsg.str();
  }

  auto maybe_exp = _parse_int<T>(exp, 10);
  if (auto err = std::get_if<std::string>(&maybe_exp))
  {
    errmsg << "Exponent part of scientific literal is not a valid number: "
           << exp << ": " << err;
    return errmsg.str();
  }

  auto c = std::get<T>(maybe_coeff);
  auto e = std::get<T>(maybe_exp);

  if (c > 9)
  {
    errmsg << "Coefficient part of scientific literal must be in range (0,9), "
              "got: "
           << coeff;
    return errmsg.str();
  }

  if (e > 16)
  {
    errmsg << "Exponent will overflow integer range: " << exp;
    return errmsg.str();
  }

  return c * (T)_ten_pow(e);
}

} // namespace

namespace bpftrace {
namespace ast {
namespace int_parser {

template <typename T>
T to_int(const std::string &num, int base)
{
  std::string n(num);
  n.erase(std::remove(n.begin(), n.end(), '_'), n.end());

  std::variant<T, std::string> res;

  auto pos = n.find_first_of("eE");
  if (pos != std::string::npos)
  {
    res = _parse_exp<T>(n.substr(0, pos), n.substr(pos + 1, std::string::npos));
  }
  else
  {
    res = _parse_int<T>(n, base);
  }

  if (auto err = std::get_if<std::string>(&res))
    throw std::invalid_argument(*err);
  return std::get<T>(res);
}

int64_t to_int(const std::string &num, int base)
{
  return to_int<int64_t>(num, base);
}

uint64_t to_uint(const std::string &num, int base)
{
  return to_int<uint64_t>(num, base);
}

} // namespace int_parser
} // namespace ast
} // namespace bpftrace
<commit_msg>int_parser: print the actual error<commit_after>#include <algorithm>
#include <exception>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <variant>

#include "int_parser.h"

namespace {

template <typename T>
T _parse_int(const std::string &num __attribute__((unused)),
             size_t *idx __attribute__((unused)),
             int base __attribute__((unused)))
{
  static_assert(not std::is_same_v<T, T>,
                "BUG: _parse_int not implemented for type");
}

template <>
int64_t _parse_int(const std::string &num, size_t *idx, int base)
{
  return std::stoll(num, idx, base);
}

template <>
uint64_t _parse_int(const std::string &num, size_t *idx, int base)
{
  return std::stoull(num, idx, base);
}

template <typename T>
std::variant<T, std::string> _parse_int(const std::string &num, int base)
{
  // https://en.cppreference.com/w/cpp/language/integer_literal#The_type_of_the_literal
  static auto int_size_re = std::regex("^(u|u?l?l)$", std::regex::icase);
  try
  {
    std::size_t idx;
    T ret = _parse_int<T>(num, &idx, base);

    if (idx != num.size())
    {
      auto trail = num.substr(idx, std::string::npos);
      auto match = std::regex_match(trail, int_size_re);

      if (!match)
        return "Found trailing non-numeric characters";
    }

    return ret;
  }
  catch (const std::exception &ex)
  {
    return ex.what();
  }
}

// integer variant of   10^exp
uint64_t _ten_pow(uint64_t exp)
{
  static const uint64_t v[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
  if (exp > 6)
    return v[6] * _ten_pow(exp - 6);
  return v[exp];
}

// integer variant of scientific notation parsing
template <typename T>
std::variant<T, std::string> _parse_exp(const std::string &coeff,
                                        const std::string &exp)
{
  std::stringstream errmsg;
  auto maybe_coeff = _parse_int<T>(coeff, 10);
  if (std::string *err = std::get_if<std::string>(&maybe_coeff))
  {
    errmsg << "Coefficient part of scientific literal is not a valid number: "
           << coeff << ": " << *err;
    return errmsg.str();
  }

  auto maybe_exp = _parse_int<T>(exp, 10);
  if (std::string *err = std::get_if<std::string>(&maybe_exp))
  {
    errmsg << "Exponent part of scientific literal is not a valid number: "
           << exp << ": " << *err;
    return errmsg.str();
  }

  auto c = std::get<T>(maybe_coeff);
  auto e = std::get<T>(maybe_exp);

  if (c > 9)
  {
    errmsg << "Coefficient part of scientific literal must be in range (0,9), "
              "got: "
           << coeff;
    return errmsg.str();
  }

  if (e > 16)
  {
    errmsg << "Exponent will overflow integer range: " << exp;
    return errmsg.str();
  }

  return c * (T)_ten_pow(e);
}

} // namespace

namespace bpftrace {
namespace ast {
namespace int_parser {

template <typename T>
T to_int(const std::string &num, int base)
{
  std::string n(num);
  n.erase(std::remove(n.begin(), n.end(), '_'), n.end());

  std::variant<T, std::string> res;

  auto pos = n.find_first_of("eE");
  if (pos != std::string::npos)
  {
    res = _parse_exp<T>(n.substr(0, pos), n.substr(pos + 1, std::string::npos));
  }
  else
  {
    res = _parse_int<T>(n, base);
  }

  if (std::string *err = std::get_if<std::string>(&res))
    throw std::invalid_argument(*err);
  return std::get<T>(res);
}

int64_t to_int(const std::string &num, int base)
{
  return to_int<int64_t>(num, base);
}

uint64_t to_uint(const std::string &num, int base)
{
  return to_int<uint64_t>(num, base);
}

} // namespace int_parser
} // namespace ast
} // namespace bpftrace
<|endoftext|>


<commit_before>#pragma once

#include <cstddef>
#include <memory>
#include <uv.h>
#include "util.hpp"

namespace uvw {

struct BaseEvent {
    virtual ~BaseEvent() noexcept = 0;

    static std::size_t next() noexcept {
        static std::size_t cnt = 0;
        return cnt++;
    }
};

BaseEvent::~BaseEvent() noexcept { }

template<typename E>
struct Event: BaseEvent {
    static std::size_t type() noexcept {
        static std::size_t val = BaseEvent::next();
        return val;
    }
};

struct AsyncEvent: Event<AsyncEvent> { };
struct CheckEvent: Event<CheckEvent> { };
struct CloseEvent: Event<CloseEvent> { };
struct ConnectEvent: Event<ConnectEvent> { };

struct DataEvent: Event<DataEvent> {
    explicit DataEvent(std::unique_ptr<const char[]> ptr, ssize_t l) noexcept
        : dt{std::move(ptr)}, len{l}
    { }

    const char * data() const noexcept { return dt.get(); }
    ssize_t length() const noexcept { return len; }

private:
    std::unique_ptr<const char[]> dt;
    const ssize_t len;
};

struct EndEvent: Event<EndEvent> { };

struct ErrorEvent: Event<ErrorEvent> {
    explicit ErrorEvent(int code = 0) noexcept: ec(code) { }

    const char * what() const noexcept { return uv_strerror(ec); }
    int code() const noexcept { return ec; }

private:
    const int ec;
};

template<typename E>
struct FlagsEvent: Event<FlagsEvent<E>> {
    explicit FlagsEvent(Flags<E> f) noexcept: flgs{std::move(f)} { }

    Flags<E> flags() const noexcept { return flgs; }

private:
    Flags<E> flgs;
};

struct FsPollEvent: Event<FsPollEvent> {
    explicit FsPollEvent(const Stat &p, const Stat &c) noexcept
        : prev(p), curr(c)
    { }

    const Stat & previous() const noexcept { return prev; }
    const Stat & current() const noexcept { return curr; }

private:
    Stat prev;
    Stat curr;
};

struct IdleEvent: Event<IdleEvent> { };
struct ListenEvent: Event<ListenEvent> { };
struct PrepareEvent: Event<PrepareEvent> { };
struct SendEvent: Event<SendEvent> { };
struct ShutdownEvent: Event<ShutdownEvent> { };

struct SignalEvent: Event<SignalEvent> {
    explicit SignalEvent(int sig) noexcept: signum(sig) { }

    int signal() const noexcept { return signum; }

private:
    const int signum;
};

struct TimerEvent: Event<TimerEvent> { };

struct UDPDataEvent: Event<UDPDataEvent> {
    explicit UDPDataEvent(Addr addr, std::unique_ptr<const char[]> ptr, ssize_t l, bool trunc) noexcept
        : dt{std::move(ptr)}, len{l}, sndr{addr}, part{trunc}
    { }

    const char * data() const noexcept { return dt.get(); }
    ssize_t length() const noexcept { return len; }
    Addr sender() const noexcept { return sndr; }
    bool partial() const noexcept { return part; }

private:
    std::unique_ptr<const char[]> dt;
    const ssize_t len;
    Addr sndr;
    const bool part;
};

struct UninitializedEvent: Event<UninitializedEvent> { };
struct WorkEvent: Event<WorkEvent> { };
struct WriteEvent: Event<WriteEvent> { };

}
<commit_msg>review: events<commit_after>#pragma once

#include <cstddef>
#include <memory>
#include <uv.h>
#include "util.hpp"

namespace uvw {

// base structures

struct BaseEvent {
    virtual ~BaseEvent() noexcept = 0;

    static std::size_t next() noexcept {
        static std::size_t cnt = 0;
        return cnt++;
    }
};

BaseEvent::~BaseEvent() noexcept { }

template<typename E>
struct Event: BaseEvent {
    static std::size_t type() noexcept {
        static std::size_t val = BaseEvent::next();
        return val;
    }
};

// empty events

struct DefaultEvent: Event<DefaultEvent> { };

using AsyncEvent = DefaultEvent;
using CheckEvent = DefaultEvent;
using CloseEvent = DefaultEvent;
using ConnectEvent = DefaultEvent;
using EndEvent = DefaultEvent;
using IdleEvent = DefaultEvent;
using ListenEvent = DefaultEvent;
using PrepareEvent = DefaultEvent;
using SendEvent = DefaultEvent;
using ShutdownEvent = DefaultEvent;
using TimerEvent = DefaultEvent;
using UninitializedEvent = DefaultEvent;
using WorkEvent = DefaultEvent;
using WriteEvent = DefaultEvent;

// specialized events

struct DataEvent: Event<DataEvent> {
    explicit DataEvent(std::unique_ptr<const char[]> ptr, ssize_t l) noexcept
        : dt{std::move(ptr)}, len{l}
    { }

    const char * data() const noexcept { return dt.get(); }
    ssize_t length() const noexcept { return len; }

private:
    std::unique_ptr<const char[]> dt;
    const ssize_t len;
};

struct ErrorEvent: Event<ErrorEvent> {
    explicit ErrorEvent(int code = 0) noexcept: ec(code) { }

    const char * what() const noexcept { return uv_strerror(ec); }
    int code() const noexcept { return ec; }

private:
    const int ec;
};

template<typename E>
struct FlagsEvent: Event<FlagsEvent<E>> {
    explicit FlagsEvent(Flags<E> f) noexcept: flgs{std::move(f)} { }

    Flags<E> flags() const noexcept { return flgs; }

private:
    Flags<E> flgs;
};

struct FsPollEvent: Event<FsPollEvent> {
    explicit FsPollEvent(const Stat &p, const Stat &c) noexcept
        : prev(p), curr(c)
    { }

    const Stat & previous() const noexcept { return prev; }
    const Stat & current() const noexcept { return curr; }

private:
    Stat prev;
    Stat curr;
};

struct SignalEvent: Event<SignalEvent> {
    explicit SignalEvent(int sig) noexcept: signum(sig) { }

    int signal() const noexcept { return signum; }

private:
    const int signum;
};

struct UDPDataEvent: Event<UDPDataEvent> {
    explicit UDPDataEvent(Addr addr, std::unique_ptr<const char[]> ptr, ssize_t l, bool trunc) noexcept
        : dt{std::move(ptr)}, len{l}, sndr{addr}, part{trunc}
    { }

    const char * data() const noexcept { return dt.get(); }
    ssize_t length() const noexcept { return len; }
    Addr sender() const noexcept { return sndr; }
    bool partial() const noexcept { return part; }

private:
    std::unique_ptr<const char[]> dt;
    const ssize_t len;
    Addr sndr;
    const bool part;
};

}
<|endoftext|>