<commit_before>/*
 * Manage connections to HTTP clients.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_LB_CONNECTION_H
#define BENG_PROXY_LB_CONNECTION_H

#include "istream-direct.h"

#include <inline/list.h>

#include <stdint.h>
#include <stddef.h>

struct pool;
struct ssl_factory;
struct notify;
struct sockaddr;

struct lb_connection {
    struct list_head siblings;

    struct pool *pool;

    struct lb_instance *instance;

    const struct lb_listener_config *listener;

    const struct config *config;
    struct ssl_filter *ssl_filter;
    struct http_server_connection *http;

    /**
     * The time stamp at the start of the request.  Used to calculate
     * the request duration.
     */
    uint64_t request_start_time;

    struct lb_tcp *tcp;
};

struct lb_connection *
lb_connection_new(struct lb_instance *instance,
                  const struct lb_listener_config *listener,
                  struct ssl_factory *ssl_factory, struct notify *notify,
                  int fd, const struct sockaddr *addr, size_t addrlen);

void
lb_connection_remove(struct lb_connection *connection);

void
lb_connection_close(struct lb_connection *connection);

#endif
<commit_msg>lb_connection: include cleanup<commit_after>/*
 * Manage connections to HTTP clients.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_LB_CONNECTION_H
#define BENG_PROXY_LB_CONNECTION_H

#include <inline/list.h>

#include <stdint.h>
#include <stddef.h>

struct pool;
struct ssl_factory;
struct notify;
struct sockaddr;

struct lb_connection {
    struct list_head siblings;

    struct pool *pool;

    struct lb_instance *instance;

    const struct lb_listener_config *listener;

    const struct config *config;
    struct ssl_filter *ssl_filter;
    struct http_server_connection *http;

    /**
     * The time stamp at the start of the request.  Used to calculate
     * the request duration.
     */
    uint64_t request_start_time;

    struct lb_tcp *tcp;
};

struct lb_connection *
lb_connection_new(struct lb_instance *instance,
                  const struct lb_listener_config *listener,
                  struct ssl_factory *ssl_factory, struct notify *notify,
                  int fd, const struct sockaddr *addr, size_t addrlen);

void
lb_connection_remove(struct lb_connection *connection);

void
lb_connection_close(struct lb_connection *connection);

#endif
<|endoftext|>


<commit_before><commit_msg>FIX: Prevent situation where default format entered in preferences, overwrites prefixes on eg. circular dimensions<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"
#include "verify_fail.hpp"

#include <tao/pegtl/contrib/raw_string.hpp>

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      std::string content;  // NOLINT

      using rstring = raw_string< '[', '=', ']' >;
      using qstring = raw_string< '[', '=', ']', alpha, digit >;

      template< typename Rule >
      struct raction
         : nothing< Rule >
      {
      };

      template<>
      struct raction< rstring::content >
      {
         template< typename Input, typename... States >
         static void apply( const Input& in, const States&... /*unused*/ )
         {
            content.assign( in.begin(), in.end() );
         }
      };

      template< typename Rule >
      struct qaction
         : nothing< Rule >
      {
      };

      template<>
      struct qaction< qstring::content >
      {
         template< typename Input, typename... States >
         static void apply( const Input& in, const States&... /*unused*/ )
         {
            content.assign( in.begin(), in.end() );
         }
      };

      struct rgrammar
         : must< rstring, eof >
      {
      };

      struct qgrammar
         : must< qstring, eof >
      {
      };

      template< typename Rule, template< typename > class Action, unsigned M, unsigned N >
      void verify_data( const std::size_t line, const char* file, const char ( &m )[ M ], const char ( &n )[ N ] )
      {
         content.clear();
         memory_input in( m, m + M - 1, file, 0, line, 0 );
         const auto r = parse< Rule, Action >( in );
         if( ( !r ) || ( content != std::string( n, N - 1 ) ) ) {
            TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r << " ]" );
         }
         content.clear();
         memory_input< tracking_mode::lazy > in2( m, m + M - 1, file, 0, line, 0 );
         const auto r2 = parse< Rule, Action >( in2 );
         if( ( !r2 ) || ( content != std::string( n, N - 1 ) ) ) {
            TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] with tracking_mode::lazy expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r2 << " ]" );
         }
      }

      void unit_test()
      {
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[]]", "" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[foo]]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[foo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\nfoo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\r\nfoo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\0\0\0]===]", "\0\0\0" );

         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[[]]", "" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[[a1]]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[a1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[\na1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[\r\na1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[a0a1a2a3]===]", "a0a1a2a3" );

         verify_fail< rgrammar >( __LINE__, __FILE__, "" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]=" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[[]] " );
         verify_fail< rgrammar >( __LINE__, __FILE__, " [[]]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]-]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[-[]=]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[-[]-]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[===[]====]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[====[]===]" );

         verify_fail< qgrammar >( __LINE__, __FILE__, "" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]=" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[[]] " );
         verify_fail< qgrammar >( __LINE__, __FILE__, " [[]]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]-]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[-[]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[-[]-]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[===[]====]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[====[]===]" );

         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[-]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[1]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a+]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[aa]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[11]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a1a]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a1aa]=]" );
      }

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#include "main.hpp"
<commit_msg>Use string_view<commit_after>// Copyright (c) 2016-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"
#include "verify_fail.hpp"

#include <tao/pegtl/contrib/raw_string.hpp>

namespace tao
{
   namespace TAO_PEGTL_NAMESPACE
   {
      std::string content;  // NOLINT

      using rstring = raw_string< '[', '=', ']' >;
      using qstring = raw_string< '[', '=', ']', alpha, digit >;

      template< typename Rule >
      struct raction
         : nothing< Rule >
      {
      };

      template<>
      struct raction< rstring::content >
      {
         template< typename Input, typename... States >
         static void apply( const Input& in, const States&... /*unused*/ )
         {
            content.assign( in.begin(), in.end() );
         }
      };

      template< typename Rule >
      struct qaction
         : nothing< Rule >
      {
      };

      template<>
      struct qaction< qstring::content >
      {
         template< typename Input, typename... States >
         static void apply( const Input& in, const States&... /*unused*/ )
         {
            content.assign( in.begin(), in.end() );
         }
      };

      struct rgrammar
         : must< rstring, eof >
      {
      };

      struct qgrammar
         : must< qstring, eof >
      {
      };

      template< typename Rule, template< typename > class Action, unsigned M, unsigned N >
      void verify_data( const std::size_t line, const char* file, const char ( &m )[ M ], const char ( &n )[ N ] )
      {
         content.clear();
         memory_input in( m, m + M - 1, file, 0, line, 0 );
         const auto r = parse< Rule, Action >( in );
         if( ( !r ) || ( content != std::string_view( n, N - 1 ) ) ) {
            TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r << " ]" );
         }
         content.clear();
         memory_input< tracking_mode::lazy > in2( m, m + M - 1, file, 0, line, 0 );
         const auto r2 = parse< Rule, Action >( in2 );
         if( ( !r2 ) || ( content != std::string_view( n, N - 1 ) ) ) {
            TAO_PEGTL_TEST_FAILED( "input data [ '" << m << "' ] with tracking_mode::lazy expected success with [ '" << n << "' ] but got [ '" << content << "' ] result [ " << r2 << " ]" );
         }
      }

      void unit_test()
      {
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[]]", "" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[foo]]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[foo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\nfoo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\r\nfoo]===]", "foo" );
         verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[\0\0\0]===]", "\0\0\0" );

         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[[]]", "" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[[a1]]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[a1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[\na1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[\r\na1]===]", "a1" );
         verify_data< qgrammar, qaction >( __LINE__, __FILE__, "[===[a0a1a2a3]===]", "a0a1a2a3" );

         verify_fail< rgrammar >( __LINE__, __FILE__, "" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]=" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[[]] " );
         verify_fail< rgrammar >( __LINE__, __FILE__, " [[]]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[=[]-]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[-[]=]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[-[]-]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[===[]====]" );
         verify_fail< rgrammar >( __LINE__, __FILE__, "[====[]===]" );

         verify_fail< qgrammar >( __LINE__, __FILE__, "" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]=" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[[]] " );
         verify_fail< qgrammar >( __LINE__, __FILE__, " [[]]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[]-]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[-[]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[-[]-]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[===[]====]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[====[]===]" );

         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[-]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[1]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a+]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[aa]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[11]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a1a]=]" );
         verify_fail< qgrammar >( __LINE__, __FILE__, "[=[a1aa]=]" );
      }

   }  // namespace TAO_PEGTL_NAMESPACE

}  // namespace tao

#include "main.hpp"
<|endoftext|>


<commit_before>/*
 * High level "Local HTTP" client.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "lhttp_request.hxx"
#include "lhttp_stock.hxx"
#include "lhttp_address.hxx"
#include "http_response.hxx"
#include "http_client.hxx"
#include "http_headers.hxx"
#include "lease.hxx"
#include "istream/istream.hxx"
#include "header_writer.hxx"
#include "pool.hxx"

struct lhttp_request {
    LhttpStock *lhttp_stock;
    StockItem *stock_item;
};

/*
 * socket lease
 *
 */

static void
lhttp_socket_release(bool reuse, void *ctx)
{
    struct lhttp_request *request = (struct lhttp_request *)ctx;

    lhttp_stock_put(request->lhttp_stock, *request->stock_item, !reuse);
}

static const struct lease lhttp_socket_lease = {
    .release = lhttp_socket_release,
};

/*
 * constructor
 *
 */

void
lhttp_request(struct pool &pool, LhttpStock &lhttp_stock,
              const LhttpAddress &address,
              http_method_t method, HttpHeaders &&headers,
              struct istream *body,
              const struct http_response_handler &handler, void *handler_ctx,
              struct async_operation_ref &async_ref)
{
    GError *error = nullptr;
    if (!address.options.Check(&error)) {
        if (body != nullptr)
            istream_close(body);

        handler.InvokeAbort(handler_ctx, error);
        return;
    }

    auto request = NewFromPool<struct lhttp_request>(pool);
    request->lhttp_stock = &lhttp_stock;

    StockItem *stock_item =
        lhttp_stock_get(&lhttp_stock, &pool, &address,
                        &error);
    if (stock_item == nullptr) {
        if (body != nullptr)
            istream_close(body);

        handler.InvokeAbort(handler_ctx, error);
        return;
    }

    request->stock_item = stock_item;

    if (address.host_and_port != nullptr)
        headers.Write(pool, "host", address.host_and_port);

    http_client_request(pool,
                        lhttp_stock_item_get_socket(*stock_item),
                        lhttp_stock_item_get_type(*stock_item),
                        lhttp_socket_lease, request,
                        lhttp_stock_item_get_name(*stock_item),
                        nullptr, nullptr,
                        method, address.uri, std::move(headers), body, true,
                        handler, handler_ctx,
                        async_ref);
}
<commit_msg>lhttp_request: rename struct with CamelCase<commit_after>/*
 * High level "Local HTTP" client.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "lhttp_request.hxx"
#include "lhttp_stock.hxx"
#include "lhttp_address.hxx"
#include "http_response.hxx"
#include "http_client.hxx"
#include "http_headers.hxx"
#include "lease.hxx"
#include "istream/istream.hxx"
#include "header_writer.hxx"
#include "pool.hxx"

struct LhttpRequest {
    LhttpStock *lhttp_stock;
    StockItem *stock_item;
};

/*
 * socket lease
 *
 */

static void
lhttp_socket_release(bool reuse, void *ctx)
{
    auto *request = (LhttpRequest *)ctx;

    lhttp_stock_put(request->lhttp_stock, *request->stock_item, !reuse);
}

static const struct lease lhttp_socket_lease = {
    .release = lhttp_socket_release,
};

/*
 * constructor
 *
 */

void
lhttp_request(struct pool &pool, LhttpStock &lhttp_stock,
              const LhttpAddress &address,
              http_method_t method, HttpHeaders &&headers,
              struct istream *body,
              const struct http_response_handler &handler, void *handler_ctx,
              struct async_operation_ref &async_ref)
{
    GError *error = nullptr;
    if (!address.options.Check(&error)) {
        if (body != nullptr)
            istream_close(body);

        handler.InvokeAbort(handler_ctx, error);
        return;
    }

    auto request = NewFromPool<LhttpRequest>(pool);
    request->lhttp_stock = &lhttp_stock;

    StockItem *stock_item =
        lhttp_stock_get(&lhttp_stock, &pool, &address,
                        &error);
    if (stock_item == nullptr) {
        if (body != nullptr)
            istream_close(body);

        handler.InvokeAbort(handler_ctx, error);
        return;
    }

    request->stock_item = stock_item;

    if (address.host_and_port != nullptr)
        headers.Write(pool, "host", address.host_and_port);

    http_client_request(pool,
                        lhttp_stock_item_get_socket(*stock_item),
                        lhttp_stock_item_get_type(*stock_item),
                        lhttp_socket_lease, request,
                        lhttp_stock_item_get_name(*stock_item),
                        nullptr, nullptr,
                        method, address.uri, std::move(headers), body, true,
                        handler, handler_ctx,
                        async_ref);
}
<|endoftext|>


<commit_before>#include <ktextedit.h>
#include <kaction.h>
#include <kcolordialog.h>
#include <kfontdialog.h>
#include <kdebug.h>
#include <kparts/genericfactory.h>

#include "krichtexteditpart.h"
#include "krichtexteditpart.moc"

typedef KParts::GenericFactory<KopeteRichTextEditPart> KopeteRichTextEditPartFactory;
K_EXPORT_COMPONENT_FACTORY( libkopeterichtexteditpart,  KopeteRichTextEditPartFactory )

KopeteRichTextEditPart::KopeteRichTextEditPart( QWidget *wparent, const char *wname, QObject*, const char*, const QStringList& )
	: KParts::ReadOnlyPart( wparent, wname ? wname : "rich_text_part" )
{
	KopeteRichTextEditPart::KopeteRichTextEditPart( wparent, wname, false );
}

KopeteRichTextEditPart::KopeteRichTextEditPart( QWidget *parent, const char *name, bool supportsRichText )
  : KParts::ReadOnlyPart( parent, name ? name : "rich_text_part" )
{
	// we need an instance
	setInstance( KopeteRichTextEditPartFactory::instance() );

	editor = new KTextEdit( parent );
	editor->setReadOnly( false );

	simpleMode = !supportsRichText;
	setWidget( editor );
	createActions();

	if( simpleMode ) //Only modidy bg and fg color and font
	{
		editor->setTextFormat( Qt::PlainText );
		setXMLFile( "kopeterichtexteditpartsimple.rc" );
	}
	else //Modify rich text
	{
		editor->setTextFormat( Qt::RichText );
		setXMLFile( "kopeterichtexteditpartfull.rc" );
	}
}

void KopeteRichTextEditPart::createActions()
{
	createActions( actionCollection() );
}

KAboutData *KopeteRichTextEditPart::createAboutData()
{
	KAboutData *aboutData = new KAboutData("kopeterichtexteditpart", I18N_NOOP("KopeteRichTextEditPart"), "0.1",
						I18N_NOOP("A simple rich text editor part for Kopete"),
						KAboutData::License_LGPL );
	aboutData->addAuthor("Richard J. Moore", 0, "rich@kde.org", "http://xmelegance.org/" );
	aboutData->addAuthor("Jason Keirstead", 0, "jason@keirstead.org", "http://www.keirstead.org/" );
	return aboutData;
}

void KopeteRichTextEditPart::createActions( KActionCollection *ac )
{
	(void) new KAction( i18n("Text &Color..."), "color_line", 0,
		this, SLOT( setFgColor() ),
		ac, "format_color" );

	(void) new KAction( i18n("Background Co&lor..."), "color_fill", 0,
		this, SLOT( setBgColor() ),
		ac, "format_bgcolor" );

	action_font = new KFontAction( i18n("&Font"), 0,
			ac, "format_font" );
	connect( action_font, SIGNAL( activated( const QString & ) ),
		this, SLOT( setFont( const QString & ) ) );

	action_font_size = new KFontSizeAction( i18n("Font &Size"), 0,
			ac, "format_font_size" );
	connect( action_font_size, SIGNAL( fontSizeChanged(int) ),
		editor, SLOT( setPointSize(int) ) );

	if( !simpleMode )
	{
		action_bold = new KToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
				ac, "format_bold" );
		connect( action_bold, SIGNAL( toggled(bool) ),
			editor, SLOT( setBold(bool) ) );

		action_italic = new KToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
				ac, "format_italic" );
		connect( action_italic, SIGNAL( toggled(bool) ),
			editor, SLOT( setItalic(bool) ) );

		action_underline = new KToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
					ac, "format_underline" );
		connect( action_underline, SIGNAL( toggled(bool) ),
			editor, SLOT( setUnderline(bool) ) );

		action_align_left = new KToggleAction( i18n("Align &Left"), "text_left", 0,
				ac, "format_align_left" );
		connect( action_align_left, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignLeft(bool) ) );

		action_align_center = new KToggleAction( i18n("Align &Center"), "text_center", 0,
				ac, "format_align_center" );
		connect( action_align_center, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignCenter(bool) ) );

		action_align_right = new KToggleAction( i18n("Align &Right"), "text_right", 0,
				ac, "format_align_right" );
		connect( action_align_right, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignRight(bool) ) );

		action_align_justify = new KToggleAction( i18n("&Justify"), "text_block", 0,
				ac, "format_align_justify" );
		connect( action_align_justify, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignJustify(bool) ) );

		action_align_left->setExclusiveGroup( "alignment" );
		action_align_center->setExclusiveGroup( "alignment" );
		action_align_right->setExclusiveGroup( "alignment" );
		action_align_justify->setExclusiveGroup( "alignment" );

		connect( editor, SIGNAL( currentFontChanged( const QFont & ) ),
			this, SLOT( updateCharFmt() ) );
		connect( editor, SIGNAL( cursorPositionChanged( int,int ) ),
			this, SLOT( updateAligment() ) );

		updateCharFmt();
		updateAligment();
	}

	connect( editor, SIGNAL( currentFontChanged( const QFont & ) ),
		this, SLOT( updateFont() ) );

	updateFont();
}

void KopeteRichTextEditPart::updateCharFmt()
{
	action_bold->setChecked( editor->bold() );
	action_italic->setChecked( editor->italic() );
	action_underline->setChecked( editor->underline() );
}

void KopeteRichTextEditPart::clear()
{
	editor->setText( QString::null );
	setFont( mFont );
	setFgColor( mFgColor );

	if( !simpleMode )
	{
		editor->setBold( action_bold->isChecked() );
		editor->setItalic( action_italic->isChecked() );
		editor->setUnderline( action_underline->isChecked() );
	}
}

void KopeteRichTextEditPart::updateAligment()
{
	int align = editor->alignment();

	switch ( align )
	{
		case AlignRight:
			action_align_right->setChecked( true );
			break;
		case AlignCenter:
			action_align_center->setChecked( true );
			break;
		case AlignLeft:
			action_align_left->setChecked( true );
			break;
		case AlignJustify:
			action_align_justify->setChecked( true );
			break;
		default:
			break;
	}
}

void KopeteRichTextEditPart::updateFont()
{
	if ( editor->pointSize() > 0 )
		action_font_size->setFontSize( editor->pointSize() );
	action_font->setFont( editor->family() );
}

void KopeteRichTextEditPart::setFgColor()
{
	QColor col;

	int s = KColorDialog::getColor( col, editor->color(), editor );
	if ( s != QDialog::Accepted )
		return;

	setFgColor( col );
}

void KopeteRichTextEditPart::setFgColor( const QColor &newColor )
{
	mFgColor = newColor;

	if( simpleMode )
	{
		QPalette pal = editor->palette();
		pal.setColor(QPalette::Active, QColorGroup::Text, mFgColor );
		pal.setColor(QPalette::Inactive, QColorGroup::Text, mFgColor );

		if ( pal == QApplication::palette( editor ) )
			editor->unsetPalette();
		else
			editor->setPalette(pal);
	}

	editor->setColor( mFgColor );
}

void KopeteRichTextEditPart::setBgColor()
{
	QColor col;

	int s = KColorDialog::getColor( col, mBgColor, editor );
	if ( s != QDialog::Accepted )
		return;

	setBgColor( col );
}

void KopeteRichTextEditPart::setBgColor( const QColor &newColor )
{
	mBgColor = newColor;

	QPalette pal = editor->palette();
	pal.setColor(QPalette::Active, QColorGroup::Base, mBgColor );
	pal.setColor(QPalette::Inactive, QColorGroup::Base, mBgColor );
	pal.setColor(QPalette::Disabled, QColorGroup::Base, mBgColor );

	if ( pal == QApplication::palette( editor ) )
		editor->unsetPalette();
	else
		editor->setPalette(pal);
}

void KopeteRichTextEditPart::setFont()
{
	KFontDialog::getFont(mFont, false, editor);
	setFont(mFont);
	updateFont();
}

void KopeteRichTextEditPart::setFont( const QFont &newFont )
{
	mFont = newFont;
	editor->setFont(mFont);
}

void KopeteRichTextEditPart::setFont( const QString &newFont )
{
	editor->setFamily(newFont);
	mFont = editor->font();
}

void KopeteRichTextEditPart::setAlignLeft( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignLeft );
}

void KopeteRichTextEditPart::setAlignRight( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignRight );
}

void KopeteRichTextEditPart::setAlignCenter( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignCenter );
}

void KopeteRichTextEditPart::setAlignJustify( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignJustify );
}
<commit_msg>Trivial patch.<commit_after>#include <ktextedit.h>
#include <kaction.h>
#include <kcolordialog.h>
#include <kfontdialog.h>
#include <kdebug.h>
#include <kdeversion.h>
#include <kparts/genericfactory.h>

#include "krichtexteditpart.h"
#include "krichtexteditpart.moc"

typedef KParts::GenericFactory<KopeteRichTextEditPart> KopeteRichTextEditPartFactory;
K_EXPORT_COMPONENT_FACTORY( libkopeterichtexteditpart,  KopeteRichTextEditPartFactory )

KopeteRichTextEditPart::KopeteRichTextEditPart( QWidget *wparent, const char *wname, QObject*, const char*, const QStringList& )
	: KParts::ReadOnlyPart( wparent, wname ? wname : "rich_text_part" )
{
	KopeteRichTextEditPart::KopeteRichTextEditPart( wparent, wname, false );
}

KopeteRichTextEditPart::KopeteRichTextEditPart( QWidget *parent, const char *name, bool supportsRichText )
  : KParts::ReadOnlyPart( parent, name ? name : "rich_text_part" )
{
	// we need an instance
	setInstance( KopeteRichTextEditPartFactory::instance() );

	editor = new KTextEdit( parent );
	editor->setReadOnly( false );

	simpleMode = !supportsRichText;
	setWidget( editor );
	createActions();

	if( simpleMode ) //Only modidy bg and fg color and font
	{
		editor->setTextFormat( Qt::PlainText );
		setXMLFile( "kopeterichtexteditpartsimple.rc" );
	}
	else //Modify rich text
	{
		editor->setTextFormat( Qt::RichText );
		setXMLFile( "kopeterichtexteditpartfull.rc" );
	}

	#if KDE_IS_VERSION( 3, 1, 90 )
		editor->setCheckSpellingEnabled( true );
	#endif
}

void KopeteRichTextEditPart::createActions()
{
	createActions( actionCollection() );
}

KAboutData *KopeteRichTextEditPart::createAboutData()
{
	KAboutData *aboutData = new KAboutData("kopeterichtexteditpart", I18N_NOOP("KopeteRichTextEditPart"), "0.1",
						I18N_NOOP("A simple rich text editor part for Kopete"),
						KAboutData::License_LGPL );
	aboutData->addAuthor("Richard J. Moore", 0, "rich@kde.org", "http://xmelegance.org/" );
	aboutData->addAuthor("Jason Keirstead", 0, "jason@keirstead.org", "http://www.keirstead.org/" );
	return aboutData;
}

void KopeteRichTextEditPart::createActions( KActionCollection *ac )
{
	(void) new KAction( i18n("Text &Color..."), "color_line", 0,
		this, SLOT( setFgColor() ),
		ac, "format_color" );

	(void) new KAction( i18n("Background Co&lor..."), "color_fill", 0,
		this, SLOT( setBgColor() ),
		ac, "format_bgcolor" );

	action_font = new KFontAction( i18n("&Font"), 0,
			ac, "format_font" );
	connect( action_font, SIGNAL( activated( const QString & ) ),
		this, SLOT( setFont( const QString & ) ) );

	action_font_size = new KFontSizeAction( i18n("Font &Size"), 0,
			ac, "format_font_size" );
	connect( action_font_size, SIGNAL( fontSizeChanged(int) ),
		editor, SLOT( setPointSize(int) ) );

	if( !simpleMode )
	{
		action_bold = new KToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
				ac, "format_bold" );
		connect( action_bold, SIGNAL( toggled(bool) ),
			editor, SLOT( setBold(bool) ) );

		action_italic = new KToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
				ac, "format_italic" );
		connect( action_italic, SIGNAL( toggled(bool) ),
			editor, SLOT( setItalic(bool) ) );

		action_underline = new KToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
					ac, "format_underline" );
		connect( action_underline, SIGNAL( toggled(bool) ),
			editor, SLOT( setUnderline(bool) ) );

		action_align_left = new KToggleAction( i18n("Align &Left"), "text_left", 0,
				ac, "format_align_left" );
		connect( action_align_left, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignLeft(bool) ) );

		action_align_center = new KToggleAction( i18n("Align &Center"), "text_center", 0,
				ac, "format_align_center" );
		connect( action_align_center, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignCenter(bool) ) );

		action_align_right = new KToggleAction( i18n("Align &Right"), "text_right", 0,
				ac, "format_align_right" );
		connect( action_align_right, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignRight(bool) ) );

		action_align_justify = new KToggleAction( i18n("&Justify"), "text_block", 0,
				ac, "format_align_justify" );
		connect( action_align_justify, SIGNAL( toggled(bool) ),
			this, SLOT( setAlignJustify(bool) ) );

		action_align_left->setExclusiveGroup( "alignment" );
		action_align_center->setExclusiveGroup( "alignment" );
		action_align_right->setExclusiveGroup( "alignment" );
		action_align_justify->setExclusiveGroup( "alignment" );

		connect( editor, SIGNAL( currentFontChanged( const QFont & ) ),
			this, SLOT( updateCharFmt() ) );
		connect( editor, SIGNAL( cursorPositionChanged( int,int ) ),
			this, SLOT( updateAligment() ) );

		updateCharFmt();
		updateAligment();
	}

	connect( editor, SIGNAL( currentFontChanged( const QFont & ) ),
		this, SLOT( updateFont() ) );

	updateFont();
}

void KopeteRichTextEditPart::updateCharFmt()
{
	action_bold->setChecked( editor->bold() );
	action_italic->setChecked( editor->italic() );
	action_underline->setChecked( editor->underline() );
}

void KopeteRichTextEditPart::clear()
{
	editor->setText( QString::null );
	setFont( mFont );
	setFgColor( mFgColor );

	if( !simpleMode )
	{
		editor->setBold( action_bold->isChecked() );
		editor->setItalic( action_italic->isChecked() );
		editor->setUnderline( action_underline->isChecked() );
	}
}

void KopeteRichTextEditPart::updateAligment()
{
	int align = editor->alignment();

	switch ( align )
	{
		case AlignRight:
			action_align_right->setChecked( true );
			break;
		case AlignCenter:
			action_align_center->setChecked( true );
			break;
		case AlignLeft:
			action_align_left->setChecked( true );
			break;
		case AlignJustify:
			action_align_justify->setChecked( true );
			break;
		default:
			break;
	}
}

void KopeteRichTextEditPart::updateFont()
{
	if ( editor->pointSize() > 0 )
		action_font_size->setFontSize( editor->pointSize() );
	action_font->setFont( editor->family() );
}

void KopeteRichTextEditPart::setFgColor()
{
	QColor col;

	int s = KColorDialog::getColor( col, editor->color(), editor );
	if ( s != QDialog::Accepted )
		return;

	setFgColor( col );
}

void KopeteRichTextEditPart::setFgColor( const QColor &newColor )
{
	mFgColor = newColor;

	if( simpleMode )
	{
		QPalette pal = editor->palette();
		pal.setColor(QPalette::Active, QColorGroup::Text, mFgColor );
		pal.setColor(QPalette::Inactive, QColorGroup::Text, mFgColor );

		if ( pal == QApplication::palette( editor ) )
			editor->unsetPalette();
		else
			editor->setPalette(pal);
	}

	editor->setColor( mFgColor );
}

void KopeteRichTextEditPart::setBgColor()
{
	QColor col;

	int s = KColorDialog::getColor( col, mBgColor, editor );
	if ( s != QDialog::Accepted )
		return;

	setBgColor( col );
}

void KopeteRichTextEditPart::setBgColor( const QColor &newColor )
{
	mBgColor = newColor;

	QPalette pal = editor->palette();
	pal.setColor(QPalette::Active, QColorGroup::Base, mBgColor );
	pal.setColor(QPalette::Inactive, QColorGroup::Base, mBgColor );
	pal.setColor(QPalette::Disabled, QColorGroup::Base, mBgColor );

	if ( pal == QApplication::palette( editor ) )
		editor->unsetPalette();
	else
		editor->setPalette(pal);
}

void KopeteRichTextEditPart::setFont()
{
	KFontDialog::getFont(mFont, false, editor);
	setFont(mFont);
	updateFont();
}

void KopeteRichTextEditPart::setFont( const QFont &newFont )
{
	mFont = newFont;
	editor->setFont(mFont);
}

void KopeteRichTextEditPart::setFont( const QString &newFont )
{
	editor->setFamily(newFont);
	mFont = editor->font();
}

void KopeteRichTextEditPart::setAlignLeft( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignLeft );
}

void KopeteRichTextEditPart::setAlignRight( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignRight );
}

void KopeteRichTextEditPart::setAlignCenter( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignCenter );
}

void KopeteRichTextEditPart::setAlignJustify( bool yes )
{
	if ( yes )
		editor->setAlignment( AlignJustify );
}
<|endoftext|>


<commit_before>#ifndef RMC_UNIVERSAL
#define RMC_UNIVERSAL

#include <cstdint>
#include <utility>

namespace rmclib {

// Utility class to allow packing arbitrary stuff into a word that can
// be placed inside an atomic in a mildly intelligent way.  (Currently
// we skip the intelligence, though, and we always just allocate an
// object for it.)

class universal {
private:
    uintptr_t val_{0};

public:
    universal() noexcept {}

    template <typename T>
    explicit
    universal(const T &t) {
        T *p = new T(t);
        val_ = reinterpret_cast<uintptr_t>(p);
    }
    template <typename T>
    explicit
    universal(T &&t) {
        T *p = new T(std::move(t));
        val_ = reinterpret_cast<uintptr_t>(p);
    }

    template <typename T>
    T extract() {
        T *p = reinterpret_cast<T *>(val_);
        T ret(std::move(*p));
        delete p;
        return ret;
    }
};

}

#endif
<commit_msg>Refactor the universal stuff a bit<commit_after>#ifndef RMC_UNIVERSAL
#define RMC_UNIVERSAL

#include <cstdint>
#include <utility>

namespace rmclib {

// Utility class to allow packing arbitrary stuff into a word that can
// be placed inside an atomic in a mildly intelligent way.  (Currently
// we skip the intelligence, though, and we always just allocate an
// object for it.)

namespace detail {

template<typename T>
struct to_uint {
    static uintptr_t into_uint(const T &t) {
        T *p = new T(t);
        return reinterpret_cast<uintptr_t>(p);
    }
    static uintptr_t into_uint(T &&t) {
        T *p = new T(std::move(t));
        return reinterpret_cast<uintptr_t>(p);
    }
    static T from_uint(uintptr_t val) {
        T *p = reinterpret_cast<T *>(val);
        T ret(std::move(*p));
        delete p;
        return ret;
    }
};

}

class universal {
private:
    uintptr_t val_{0};
    template<typename T>
    using to_uint = detail::to_uint<T>;

public:
    universal() noexcept {}

    template <typename T>
    explicit universal(const T &t) : val_(to_uint<T>::into_uint(t)) { }

    template <typename T>
    explicit universal(T &&t) :
        val_(to_uint<T>::into_uint(std::move(t))) { }

    template <typename T>
    T extract() {
        return to_uint<T>::from_uint(val_);
    }
};

}

#endif
<|endoftext|>


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

#include "src/trace_processor/trace_database.h"

#include <functional>

namespace perfetto {
namespace trace_processor {
namespace {
constexpr uint32_t kTraceChunkSizeB = 16 * 1024 * 1024;  // 16 MB
static const char kUIntColumnName[] = "UNSIGNED INT";
static const char kULongColumnName[] = "UNSIGNED BIG INT";

bool IsColumnUInt(const char* type) {
  return strncmp(type, kUIntColumnName, sizeof(kUIntColumnName)) == 0;
}

bool IsColumnULong(const char* type) {
  return strncmp(type, kULongColumnName, sizeof(kULongColumnName)) == 0;
}
}  // namespace

TraceDatabase::TraceDatabase(base::TaskRunner* task_runner)
    : task_runner_(task_runner), weak_factory_(this) {
  static_assert(offsetof(TraceDatabase, db_) == 0,
                "SQLite database must be the first field.");
  sqlite3_open(":memory:", &db_);

  // Setup the sched slice table.
  static sqlite3_module module = SchedSliceTable::CreateModule();
  sqlite3_create_module(db_, "sched", &module, static_cast<void*>(&storage_));
}

TraceDatabase::~TraceDatabase() {
  sqlite3_close(db_);
}

void TraceDatabase::LoadTrace(BlobReader* reader,
                              std::function<void()> callback) {
  // Reset storage and start a new trace parsing task.
  storage_ = {};
  parser_.reset(new TraceParser(reader, &storage_, kTraceChunkSizeB));
  LoadTraceChunk(callback);
}

void TraceDatabase::ExecuteQuery(
    const protos::RawQueryArgs& args,
    std::function<void(protos::RawQueryResult)> callback) {
  protos::RawQueryResult proto;

  const auto& sql = args.sql_query();
  sqlite3_stmt* stmt;
  int err = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int>(sql.size()),
                               &stmt, nullptr);
  if (err) {
    callback(std::move(proto));
    return;
  }

  for (int i = 0, size = sqlite3_column_count(stmt); i < size; i++) {
    // Setup the descriptors.
    auto* descriptor = proto.add_column_descriptors();
    descriptor->set_name(sqlite3_column_name(stmt, i));

    const char* type = sqlite3_column_decltype(stmt, i);
    if (IsColumnUInt(type)) {
      descriptor->set_type(protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_INT);
    } else if (IsColumnULong(type)) {
      descriptor->set_type(
          protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_LONG);
    } else {
      PERFETTO_FATAL("Unexpected column type found in SQL query");
    }

    // Add the empty column to the proto.
    proto.add_columns();
  }

  int row_count = 0;
  for (int r = sqlite3_step(stmt); r == SQLITE_ROW; r = sqlite3_step(stmt)) {
    for (int i = 0; i < proto.columns_size(); i++) {
      auto* column = proto.mutable_columns(i);
      switch (proto.column_descriptors(i).type()) {
        case protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_LONG:
          column->add_ulong_values(
              static_cast<uint64_t>(sqlite3_column_int64(stmt, i)));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_INT:
          column->add_uint_values(
              static_cast<uint32_t>(sqlite3_column_double(stmt, i)));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_INT:
        case protos::RawQueryResult_ColumnDesc_Type_LONG:
        case protos::RawQueryResult_ColumnDesc_Type_STRING:
          PERFETTO_FATAL("Unexpected column type found in SQL query");
          break;
      }
    }
    row_count++;
  }
  proto.set_num_records(static_cast<uint64_t>(row_count));

  callback(std::move(proto));
}

void TraceDatabase::LoadTraceChunk(std::function<void()> callback) {
  bool has_more = parser_->ParseNextChunk();
  if (!has_more) {
    callback();
    return;
  }

  auto weak_this = weak_factory_.GetWeakPtr();
  task_runner_->PostTask([weak_this, callback] {
    if (!weak_this)
      return;

    weak_this->LoadTraceChunk(callback);
  });
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix build when offsetof was being used on non-POD am: 4ce4cb8263 am: 008381a2d7<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/trace_database.h"

#include <functional>

namespace perfetto {
namespace trace_processor {
namespace {
constexpr uint32_t kTraceChunkSizeB = 16 * 1024 * 1024;  // 16 MB
static const char kUIntColumnName[] = "UNSIGNED INT";
static const char kULongColumnName[] = "UNSIGNED BIG INT";

bool IsColumnUInt(const char* type) {
  return strncmp(type, kUIntColumnName, sizeof(kUIntColumnName)) == 0;
}

bool IsColumnULong(const char* type) {
  return strncmp(type, kULongColumnName, sizeof(kULongColumnName)) == 0;
}
}  // namespace

TraceDatabase::TraceDatabase(base::TaskRunner* task_runner)
    : task_runner_(task_runner), weak_factory_(this) {
  sqlite3_open(":memory:", &db_);

  // Setup the sched slice table.
  static sqlite3_module module = SchedSliceTable::CreateModule();
  sqlite3_create_module(db_, "sched", &module, static_cast<void*>(&storage_));
}

TraceDatabase::~TraceDatabase() {
  sqlite3_close(db_);
}

void TraceDatabase::LoadTrace(BlobReader* reader,
                              std::function<void()> callback) {
  // Reset storage and start a new trace parsing task.
  storage_ = {};
  parser_.reset(new TraceParser(reader, &storage_, kTraceChunkSizeB));
  LoadTraceChunk(callback);
}

void TraceDatabase::ExecuteQuery(
    const protos::RawQueryArgs& args,
    std::function<void(protos::RawQueryResult)> callback) {
  protos::RawQueryResult proto;

  const auto& sql = args.sql_query();
  sqlite3_stmt* stmt;
  int err = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int>(sql.size()),
                               &stmt, nullptr);
  if (err) {
    callback(std::move(proto));
    return;
  }

  for (int i = 0, size = sqlite3_column_count(stmt); i < size; i++) {
    // Setup the descriptors.
    auto* descriptor = proto.add_column_descriptors();
    descriptor->set_name(sqlite3_column_name(stmt, i));

    const char* type = sqlite3_column_decltype(stmt, i);
    if (IsColumnUInt(type)) {
      descriptor->set_type(protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_INT);
    } else if (IsColumnULong(type)) {
      descriptor->set_type(
          protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_LONG);
    } else {
      PERFETTO_FATAL("Unexpected column type found in SQL query");
    }

    // Add the empty column to the proto.
    proto.add_columns();
  }

  int row_count = 0;
  for (int r = sqlite3_step(stmt); r == SQLITE_ROW; r = sqlite3_step(stmt)) {
    for (int i = 0; i < proto.columns_size(); i++) {
      auto* column = proto.mutable_columns(i);
      switch (proto.column_descriptors(i).type()) {
        case protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_LONG:
          column->add_ulong_values(
              static_cast<uint64_t>(sqlite3_column_int64(stmt, i)));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_UNSIGNED_INT:
          column->add_uint_values(
              static_cast<uint32_t>(sqlite3_column_double(stmt, i)));
          break;
        case protos::RawQueryResult_ColumnDesc_Type_INT:
        case protos::RawQueryResult_ColumnDesc_Type_LONG:
        case protos::RawQueryResult_ColumnDesc_Type_STRING:
          PERFETTO_FATAL("Unexpected column type found in SQL query");
          break;
      }
    }
    row_count++;
  }
  proto.set_num_records(static_cast<uint64_t>(row_count));

  callback(std::move(proto));
}

void TraceDatabase::LoadTraceChunk(std::function<void()> callback) {
  bool has_more = parser_->ParseNextChunk();
  if (!has_more) {
    callback();
    return;
  }

  auto weak_this = weak_factory_.GetWeakPtr();
  task_runner_->PostTask([weak_this, callback] {
    if (!weak_this)
      return;

    weak_this->LoadTraceChunk(callback);
  });
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>/*
 * Conway's Game of Life implementation with less than 1KB code.
 * Prototype is developed first with Arduino then ported to ATtiny84A.
 *
 * Description:
 * - cells are displayed on an 8x8 LED matrix
 * - initial setup is set through 2 pots (X and Y) and one button to select/unselect a cell
 * - starting/suspending the game is done by a second push button
 * - when the game has started, the Y pot allows speed tuning
 * - the end of game is detected when:
 *   - no cells are alive: in this case a smiley is blinking
 *   - the last generation is stable (still life): in this case the last generation is blinking
 *
 * Circuit:
 * - MCU is connected to 2 chained 74HC595 SIPO
 * - First SIPO is connected to matrix columns through 8 330Ohm resistors
 * - Second SIPO is connected to matrix rows
 *
 * Wiring:
 * - on Arduino UNO:
 *   - D2 is an output connected to both SIPO clock pins
 *   - D3 is an output connected to both SIPO latch pins
 *   - D4 is an output connected to first SIPO serial data input
 *   - D0 is an input connected to the START/STOP button (connected itself to GND)
 *   - D7 is an input connected to the SELECT button (connected itself to GND)
 *   - A0 is an analog input connected to the ROW potentiometer
 *   - A1 is an analog input connected to the COLUMN potentiometer
 * - on ATtinyX4 based boards:
 *   - PA2 is an output connected to both SIPO clock pins
 *   - PA1 is an output connected to both SIPO latch pins
 *   - PA0 is an output connected to first SIPO serial data input
 *   - PA5 is an input connected to the START/STOP button (connected itself to GND)
 *   - PA4 is an input connected to the SELECT button (connected itself to GND)
 *   - A7 is an analog input connected to the ROW potentiometer
 *   - A6 is an analog input connected to the COLUMN potentiometer
 */

// OPEN POINTS/TODO
// - Check latest optimization (no vector table) works on ATtiny circuit
// - Check compilation on UNO (may have to set same config for linker)
// - remove __jumpMain and set direcly main() instead; check if that still works

#include <avr/interrupt.h>
#include <util/delay.h>

#include <fastarduino/time.hh>
#include <fastarduino/AnalogInput.hh>

#include "Multiplexer.hh"
#include "Button.hh"
#include "Game.hh"

#if defined(ARDUINO_UNO)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D3;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D4;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A0;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A1;
static constexpr const Board::AnalogPin SPEED = Board::AnalogPin::A0;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D5;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D6;

#define HAS_TRACE 1
#elif defined (BREADBOARD_ATTINYX4)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D1;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D0;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A6;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A7;
static constexpr const Board::AnalogPin SPEED = Board::AnalogPin::A7;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D4;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D5;
#else
#error "Current target is not yet supported!"
#endif

// Trace is used only for Arduino UNO if needed
#if HAS_TRACE
#include <fastarduino/uart.hh>
USE_UATX0();
// Buffers for UART
static const uint8_t OUTPUT_BUFFER_SIZE = 128;
static char output_buffer[OUTPUT_BUFFER_SIZE];
static UATX<Board::USART::USART0> uatx{output_buffer};
FormattedOutput<OutputBuffer> trace = uatx.fout();
#endif

// Uncomment these lines if you want to quickly generate a program for a 16x16 LED matrix (default is 8x8))
//#define ROW_COUNT 16
//#define COLUMN_COUNT 16

// Those defines can be overridden in command line to support bigger LED matrices (eg 16x16)
#ifndef ROW_COUNT
#define ROW_COUNT 8
#endif
#ifndef COLUMN_COUNT
#define COLUMN_COUNT 8
#endif

// Single port used by this circuit
static constexpr const Board::Port PORT = FastPinType<CLOCK>::PORT;

// Check at compile time that all pins are on the same port
static_assert(FastPinType<LATCH>::PORT == PORT, "LATCH must be on same port as CLOCK");
static_assert(FastPinType<DATA>::PORT == PORT, "DATA must be on same port as CLOCK");
static_assert(FastPinType<SELECT>::PORT == PORT, "SELECT must be on same port as CLOCK");
static_assert(FastPinType<START_STOP>::PORT == PORT, "START_STOP must be on same port as CLOCK");

// Utility function to find the exponent of the nearest power of 2 for an integer
constexpr uint16_t LOG2(uint16_t n)
{
	return (n < 2) ? 0 : 1 + LOG2(n / 2);
}

// Timing constants
// Multiplexing is done one row every 1ms, ie 8 rows in 8ms
static constexpr const uint16_t REFRESH_PERIOD_MS = 1;
static constexpr const uint16_t REFRESH_PERIOD_US = 1000 * REFRESH_PERIOD_MS;
// Blinking LEDs are toggled every 20 times the display is fully refreshed (ie 20 x 8 x 2ms = 320ms)
static constexpr const uint16_t BLINKING_HALF_TIME_MS = 250;
static constexpr const uint16_t BLINKING_COUNTER = BLINKING_HALF_TIME_MS / REFRESH_PERIOD_MS;
// Buttons debouncing is done on a duration of 20ms
static constexpr const uint16_t DEBOUNCE_TIME_MS = 20;
static constexpr const uint8_t DEBOUNCE_COUNTER = DEBOUNCE_TIME_MS / REFRESH_PERIOD_MS;
// Minimum delay between 2 generations during phase 2 (must be a power of 2)
static constexpr const uint16_t MIN_PROGRESS_PERIOD_MS = 256;
// Delay between phase 2 (game) and phase 3 (end of game)
static constexpr const uint16_t DELAY_BEFORE_END_GAME_MS = 1000;

// Useful constants and types
static constexpr const uint8_t ROWS = ROW_COUNT;
static constexpr const uint8_t COLUMNS = COLUMN_COUNT;
using MULTIPLEXER = MatrixMultiplexer<CLOCK, LATCH, DATA, BLINKING_COUNTER, ROWS, COLUMNS>;
using ROW_TYPE = MULTIPLEXER::ROW_TYPE;
using GAME = GameOfLife<ROWS, ROW_TYPE>;

// Calculate direction of pins (3 output, 2 input with pullups)
static constexpr const uint8_t ALL_DDR = MULTIPLEXER::DDR_MASK;
static constexpr const uint8_t BUTTONS_MASK = FastPinType<SELECT>::MASK | FastPinType<START_STOP>::MASK;
static constexpr const uint8_t ALL_PORT = MULTIPLEXER::PORT_MASK | BUTTONS_MASK;

//NOTE: on the stripboards-based circuit, rows and columns are inverted
//FIXME make it size-agnostic (how??)
static constexpr const ROW_TYPE SMILEY[] =
{
	0B01110000,
	0B10001000,
	0B10000100,
	0B01000010,
	0B01000010,
	0B10000100,
	0B10001000,
	0B01110000
};

static uint16_t game_period()
{
	AnalogInput<SPEED, Board::AnalogReference::AVCC, uint8_t> speed_input;
	uint8_t period = speed_input.sample() >> 4;
	return (MIN_PROGRESS_PERIOD_MS * (period + 1)) >> LOG2(REFRESH_PERIOD_MS);
}

int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

#if HAS_TRACE
	// Setup traces (Arduino only)
	uatx.begin(57600);
	trace.width(0);
#endif

	// Initialize all pins (only one port)
	FastPort<PORT>{ALL_DDR, ALL_PORT};

	// Initialize Multiplexer
	MULTIPLEXER mux;

	// STOP button is used during both phase 1 and 2, hence declare it in global main() scope
	Button<START_STOP, DEBOUNCE_COUNTER> stop;

	// Step #1: Initialize board with 1st generation
	//===============================================
	{
		Button<SELECT, DEBOUNCE_COUNTER> select;
		AnalogInput<ROW, Board::AnalogReference::AVCC, uint8_t> row_input;
		AnalogInput<COLUMN, Board::AnalogReference::AVCC, uint8_t> column_input;
		uint8_t row = 0;
		uint8_t col = 0;
		mux.blinks()[0] = _BV(0);
		while (true)
		{
			// Update selected cell
			mux.blinks()[row] = 0;
			row = ROWS - 1 - (row_input.sample() >> (8 - LOG2(ROWS)));
			col = COLUMNS - 1 - (column_input.sample() >> (8 - LOG2(COLUMNS)));
			mux.blinks()[row] = _BV(col);
			// Check button states
			if (stop.unique_press())
				break;
			if (select.unique_press())
				mux.data()[row] ^= _BV(col);
			mux.refresh(BlinkMode::BLINK_ALL_BLINKS);
			Time::delay_us(REFRESH_PERIOD_US);
		}
	}

	// Step #2: Start game
	//=====================
	{
		// Initialize game board
		GAME game{mux.data()};

		// Loop to refresh LED matrix and progress game to next generation
		uint16_t progress_counter = 0;
		bool pause = false;
		while (true)
		{
			mux.refresh(BlinkMode::NO_BLINK);
			Time::delay_us(REFRESH_PERIOD_US);
			if (stop.unique_press())
				pause = !pause;
			if (!pause && ++progress_counter >= game_period())
			{
				game.progress_game();
				progress_counter = 0;
				// Check if game is finished (ie no more live cell, or still life)
				if (game.is_empty())
				{
					// Load a smiley into the game
					for (uint8_t i = 0; i < sizeof(SMILEY)/sizeof(SMILEY[0]); ++i)
						mux.data()[i] = SMILEY[i];
					break;
				}
				if (game.is_still())
					break;
			}
		}
	}

	// Step #3: End game
	//===================
	// Here we just need to refresh content and blink it until reset
	// First we clear multiplexer display, then we wait for one second
	mux.clear();
	Time::delay_ms(DELAY_BEFORE_END_GAME_MS);
	while (true)
	{
		Time::delay_us(REFRESH_PERIOD_US);
		mux.refresh(BlinkMode::BLINK_ALL_DATA);
	}
	return 0;
}

// Since we use -nostartfiles option we must manually set the startup code (at address 0x00)
void __jumpMain() __attribute__((naked)) __attribute__((section (".init9")));

// Startup code just clears R1 (this is expected by GCC) and calls main()
void __jumpMain()
{
	asm volatile ( ".set __stack, %0" :: "i" (RAMEND) );
	asm volatile ( "clr __zero_reg__" );	// r1 set to 0
	asm volatile ( "rjmp main");			// jump to main()
}
<commit_msg>Conway example: update UNO release code to account for different link settings on UNO.<commit_after>/*
 * Conway's Game of Life implementation with less than 1KB code.
 * Prototype is developed first with Arduino then ported to ATtiny84A.
 *
 * Description:
 * - cells are displayed on an 8x8 LED matrix
 * - initial setup is set through 2 pots (X and Y) and one button to select/unselect a cell
 * - starting/suspending the game is done by a second push button
 * - when the game has started, the Y pot allows speed tuning
 * - the end of game is detected when:
 *   - no cells are alive: in this case a smiley is blinking
 *   - the last generation is stable (still life): in this case the last generation is blinking
 *
 * Circuit:
 * - MCU is connected to 2 chained 74HC595 SIPO
 * - First SIPO is connected to matrix columns through 8 330Ohm resistors
 * - Second SIPO is connected to matrix rows
 *
 * Wiring:
 * - on Arduino UNO:
 *   - D2 is an output connected to both SIPO clock pins
 *   - D3 is an output connected to both SIPO latch pins
 *   - D4 is an output connected to first SIPO serial data input
 *   - D0 is an input connected to the START/STOP button (connected itself to GND)
 *   - D7 is an input connected to the SELECT button (connected itself to GND)
 *   - A0 is an analog input connected to the ROW potentiometer
 *   - A1 is an analog input connected to the COLUMN potentiometer
 * - on ATtinyX4 based boards:
 *   - PA2 is an output connected to both SIPO clock pins
 *   - PA1 is an output connected to both SIPO latch pins
 *   - PA0 is an output connected to first SIPO serial data input
 *   - PA5 is an input connected to the START/STOP button (connected itself to GND)
 *   - PA4 is an input connected to the SELECT button (connected itself to GND)
 *   - A7 is an analog input connected to the ROW potentiometer
 *   - A6 is an analog input connected to the COLUMN potentiometer
 */

#include <avr/interrupt.h>
#include <util/delay.h>

#include <fastarduino/time.hh>
#include <fastarduino/AnalogInput.hh>

#include "Multiplexer.hh"
#include "Button.hh"
#include "Game.hh"

#if defined(ARDUINO_UNO)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D3;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D4;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A0;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A1;
static constexpr const Board::AnalogPin SPEED = Board::AnalogPin::A0;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D5;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D6;

#define HAS_TRACE 1
#elif defined (BREADBOARD_ATTINYX4)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D1;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D0;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A6;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A7;
static constexpr const Board::AnalogPin SPEED = Board::AnalogPin::A7;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D4;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D5;
#else
#error "Current target is not yet supported!"
#endif

// Trace is used only for Arduino UNO if needed
#if HAS_TRACE
#include <fastarduino/uart.hh>
USE_UATX0();
// Buffers for UART
static const uint8_t OUTPUT_BUFFER_SIZE = 128;
static char output_buffer[OUTPUT_BUFFER_SIZE];
static UATX<Board::USART::USART0> uatx{output_buffer};
FormattedOutput<OutputBuffer> trace = uatx.fout();
#endif

// Uncomment these lines if you want to quickly generate a program for a 16x16 LED matrix (default is 8x8))
//#define ROW_COUNT 16
//#define COLUMN_COUNT 16

// Those defines can be overridden in command line to support bigger LED matrices (eg 16x16)
#ifndef ROW_COUNT
#define ROW_COUNT 8
#endif
#ifndef COLUMN_COUNT
#define COLUMN_COUNT 8
#endif

// Single port used by this circuit
static constexpr const Board::Port PORT = FastPinType<CLOCK>::PORT;

// Check at compile time that all pins are on the same port
static_assert(FastPinType<LATCH>::PORT == PORT, "LATCH must be on same port as CLOCK");
static_assert(FastPinType<DATA>::PORT == PORT, "DATA must be on same port as CLOCK");
static_assert(FastPinType<SELECT>::PORT == PORT, "SELECT must be on same port as CLOCK");
static_assert(FastPinType<START_STOP>::PORT == PORT, "START_STOP must be on same port as CLOCK");

// Utility function to find the exponent of the nearest power of 2 for an integer
constexpr uint16_t LOG2(uint16_t n)
{
	return (n < 2) ? 0 : 1 + LOG2(n / 2);
}

// Timing constants
// Multiplexing is done one row every 1ms, ie 8 rows in 8ms
static constexpr const uint16_t REFRESH_PERIOD_MS = 1;
static constexpr const uint16_t REFRESH_PERIOD_US = 1000 * REFRESH_PERIOD_MS;
// Blinking LEDs are toggled every 20 times the display is fully refreshed (ie 20 x 8 x 2ms = 320ms)
static constexpr const uint16_t BLINKING_HALF_TIME_MS = 250;
static constexpr const uint16_t BLINKING_COUNTER = BLINKING_HALF_TIME_MS / REFRESH_PERIOD_MS;
// Buttons debouncing is done on a duration of 20ms
static constexpr const uint16_t DEBOUNCE_TIME_MS = 20;
static constexpr const uint8_t DEBOUNCE_COUNTER = DEBOUNCE_TIME_MS / REFRESH_PERIOD_MS;
// Minimum delay between 2 generations during phase 2 (must be a power of 2)
static constexpr const uint16_t MIN_PROGRESS_PERIOD_MS = 256;
// Delay between phase 2 (game) and phase 3 (end of game)
static constexpr const uint16_t DELAY_BEFORE_END_GAME_MS = 1000;

// Useful constants and types
static constexpr const uint8_t ROWS = ROW_COUNT;
static constexpr const uint8_t COLUMNS = COLUMN_COUNT;
using MULTIPLEXER = MatrixMultiplexer<CLOCK, LATCH, DATA, BLINKING_COUNTER, ROWS, COLUMNS>;
using ROW_TYPE = MULTIPLEXER::ROW_TYPE;
using GAME = GameOfLife<ROWS, ROW_TYPE>;

// Calculate direction of pins (3 output, 2 input with pullups)
static constexpr const uint8_t ALL_DDR = MULTIPLEXER::DDR_MASK;
static constexpr const uint8_t BUTTONS_MASK = FastPinType<SELECT>::MASK | FastPinType<START_STOP>::MASK;
static constexpr const uint8_t ALL_PORT = MULTIPLEXER::PORT_MASK | BUTTONS_MASK;

//NOTE: on the stripboards-based circuit, rows and columns are inverted
//FIXME make it size-agnostic (how??)
static constexpr const ROW_TYPE SMILEY[] =
{
	0B01110000,
	0B10001000,
	0B10000100,
	0B01000010,
	0B01000010,
	0B10000100,
	0B10001000,
	0B01110000
};

static uint16_t game_period()
{
	AnalogInput<SPEED, Board::AnalogReference::AVCC, uint8_t> speed_input;
	uint8_t period = speed_input.sample() >> 4;
	return (MIN_PROGRESS_PERIOD_MS * (period + 1)) >> LOG2(REFRESH_PERIOD_MS);
}

int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

#if HAS_TRACE
	// Setup traces (Arduino only)
	uatx.begin(57600);
	trace.width(0);
#endif

	// Initialize all pins (only one port)
	FastPort<PORT>{ALL_DDR, ALL_PORT};

	// Initialize Multiplexer
	MULTIPLEXER mux;

	// STOP button is used during both phase 1 and 2, hence declare it in global main() scope
	Button<START_STOP, DEBOUNCE_COUNTER> stop;

	// Step #1: Initialize board with 1st generation
	//===============================================
	{
		Button<SELECT, DEBOUNCE_COUNTER> select;
		AnalogInput<ROW, Board::AnalogReference::AVCC, uint8_t> row_input;
		AnalogInput<COLUMN, Board::AnalogReference::AVCC, uint8_t> column_input;
		uint8_t row = 0;
		uint8_t col = 0;
		mux.blinks()[0] = _BV(0);
		while (true)
		{
			// Update selected cell
			mux.blinks()[row] = 0;
			row = ROWS - 1 - (row_input.sample() >> (8 - LOG2(ROWS)));
			col = COLUMNS - 1 - (column_input.sample() >> (8 - LOG2(COLUMNS)));
			mux.blinks()[row] = _BV(col);
			// Check button states
			if (stop.unique_press())
				break;
			if (select.unique_press())
				mux.data()[row] ^= _BV(col);
			mux.refresh(BlinkMode::BLINK_ALL_BLINKS);
			Time::delay_us(REFRESH_PERIOD_US);
		}
	}

	// Step #2: Start game
	//=====================
	{
		// Initialize game board
		GAME game{mux.data()};

		// Loop to refresh LED matrix and progress game to next generation
		uint16_t progress_counter = 0;
		bool pause = false;
		while (true)
		{
			mux.refresh(BlinkMode::NO_BLINK);
			Time::delay_us(REFRESH_PERIOD_US);
			if (stop.unique_press())
				pause = !pause;
			if (!pause && ++progress_counter >= game_period())
			{
				game.progress_game();
				progress_counter = 0;
				// Check if game is finished (ie no more live cell, or still life)
				if (game.is_empty())
				{
					// Load a smiley into the game
					for (uint8_t i = 0; i < sizeof(SMILEY)/sizeof(SMILEY[0]); ++i)
						mux.data()[i] = SMILEY[i];
					break;
				}
				if (game.is_still())
					break;
			}
		}
	}

	// Step #3: End game
	//===================
	// Here we just need to refresh content and blink it until reset
	// First we clear multiplexer display, then we wait for one second
	mux.clear();
	Time::delay_ms(DELAY_BEFORE_END_GAME_MS);
	while (true)
	{
		Time::delay_us(REFRESH_PERIOD_US);
		mux.refresh(BlinkMode::BLINK_ALL_DATA);
	}
	return 0;
}

#if defined (BREADBOARD_ATTINYX4)
// Since we use -nostartfiles option we must manually set the startup code (at address 0x00)
void __jumpMain() __attribute__((naked)) __attribute__((section (".init9")));

// Startup code just clears R1 (this is expected by GCC) and calls main()
void __jumpMain()
{
	asm volatile ( ".set __stack, %0" :: "i" (RAMEND) );
	asm volatile ( "clr __zero_reg__" );	// r1 set to 0
	asm volatile ( "rjmp main");			// jump to main()
}
#endif
<|endoftext|>


<commit_before>// Ouzel by Elviss Strazdins

#ifndef OUZEL_PLATFORM_DISPATCH_DATA_HPP
#define OUZEL_PLATFORM_DISPATCH_DATA_HPP

#include <stdexcept>
#include <dispatch/data.h>

namespace ouzel::platform::dispatch
{
    class Data final
    {
    public:
        explicit Data(const void* buffer,
                              size_t size,
                              dispatch_queue_t queue,
                              dispatch_block_t destructor):
            data{dispatch_data_create(buffer, size, queue, destructor)}
        {
            if (!data)
                throw std::runtime_error("Failed to create dispatch data");
        }

        ~Data()
        {
            if (data) dispatch_release(data);
        }

        Data(Data&& other) noexcept:
            data{other.data}
        {
            other.data = nullptr;
        }

        Data(const Data& other):
            data{other.data}
        {
            if (data) dispatch_retain(data);
        }

        Data& operator=(Data&& other) noexcept
        {
            if (&other == this) return *this;
            if (data) dispatch_release(data);
            data = other.data;
            other.data = nullptr;
            return *this;
        }

        Data& operator=(const Data& other) noexcept
        {
            if (&other == this) return *this;
            if (data) dispatch_release(data);
            data = other.data;
            if (data) dispatch_retain(data);
            return *this;
        }

        auto get() const noexcept
        {
            return data;
        }

    private:
        dispatch_data_t data = nullptr;
    };
}

#endif // OUZEL_PLATFORM_DISPATCH_DATA_HPP
<commit_msg>Make the copy constructor of Data noexcept<commit_after>// Ouzel by Elviss Strazdins

#ifndef OUZEL_PLATFORM_DISPATCH_DATA_HPP
#define OUZEL_PLATFORM_DISPATCH_DATA_HPP

#include <stdexcept>
#include <dispatch/data.h>

namespace ouzel::platform::dispatch
{
    class Data final
    {
    public:
        explicit Data(const void* buffer,
                              size_t size,
                              dispatch_queue_t queue,
                              dispatch_block_t destructor):
            data{dispatch_data_create(buffer, size, queue, destructor)}
        {
            if (!data)
                throw std::runtime_error("Failed to create dispatch data");
        }

        ~Data()
        {
            if (data) dispatch_release(data);
        }

        Data(Data&& other) noexcept:
            data{other.data}
        {
            other.data = nullptr;
        }

        Data(const Data& other) noexcept:
            data{other.data}
        {
            if (data) dispatch_retain(data);
        }

        Data& operator=(Data&& other) noexcept
        {
            if (&other == this) return *this;
            if (data) dispatch_release(data);
            data = other.data;
            other.data = nullptr;
            return *this;
        }

        Data& operator=(const Data& other) noexcept
        {
            if (&other == this) return *this;
            if (data) dispatch_release(data);
            data = other.data;
            if (data) dispatch_retain(data);
            return *this;
        }

        auto get() const noexcept
        {
            return data;
        }

    private:
        dispatch_data_t data = nullptr;
    };
}

#endif // OUZEL_PLATFORM_DISPATCH_DATA_HPP
<|endoftext|>


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

#include "Methcla/Audio/Engine.hpp"
#include "Methcla/Audio/Group.hpp"
#include "Methcla/Audio/Node.hpp"

using namespace Methcla::Audio;

Node::Node(Environment& env, NodeId nodeId)
    : Resource(env, nodeId)
    , m_parent(nullptr)
    , m_prev(nullptr)
    , m_next(nullptr)
{
}

Node::~Node()
{
    unlink();
}

void Node::unlink()
{
    if (m_parent)
    {
        m_parent->remove(this);
    }

    assert(m_parent == nullptr);
    assert(m_prev == nullptr);
    assert(m_next == nullptr);
}

void Node::process(size_t numFrames)
{
    doProcess(numFrames);
}

void Node::free()
{
    Environment* pEnv = &env();
    this->~Node();
    pEnv->rtMem().free(this);
}

void Node::doProcess(size_t)
{
}

void Node::setDone(Methcla_NodeDoneFlags flags)
{
    if (flags & kMethcla_NodeDoneFreeParent)
    {
        if (m_parent != nullptr)
            env().freeNode(m_parent->id());
    }
    else if (flags & kMethcla_NodeDoneFreeAllSiblings)
    {
        if (m_parent != nullptr)
            m_parent->freeAll();
    }
    else
    {
        if (flags & kMethcla_NodeDoneFreePreceeding)
        {
            if (m_prev != nullptr)
                env().freeNode(m_prev->id());
        }
        if (flags & kMethcla_NodeDoneFreeFollowing)
        {
             if (m_next != nullptr)
                 env().freeNode(m_next->id());
        }
    }
}
<commit_msg>Check for kMethcla_NodeDoneFreeSelf flag<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Methcla/Audio/Engine.hpp"
#include "Methcla/Audio/Group.hpp"
#include "Methcla/Audio/Node.hpp"

using namespace Methcla::Audio;

Node::Node(Environment& env, NodeId nodeId)
    : Resource(env, nodeId)
    , m_parent(nullptr)
    , m_prev(nullptr)
    , m_next(nullptr)
{
}

Node::~Node()
{
    unlink();
}

void Node::unlink()
{
    if (m_parent)
    {
        m_parent->remove(this);
    }

    assert(m_parent == nullptr);
    assert(m_prev == nullptr);
    assert(m_next == nullptr);
}

void Node::process(size_t numFrames)
{
    doProcess(numFrames);
}

void Node::free()
{
    Environment* pEnv = &env();
    this->~Node();
    pEnv->rtMem().free(this);
}

void Node::doProcess(size_t)
{
}

void Node::setDone(Methcla_NodeDoneFlags flags)
{
    if (flags & kMethcla_NodeDoneFreeParent)
    {
        if (m_parent != nullptr)
            env().freeNode(m_parent->id());
    }
    else if (flags & kMethcla_NodeDoneFreeAllSiblings)
    {
        if (m_parent != nullptr)
            m_parent->freeAll();
    }
    else
    {
        if (flags & kMethcla_NodeDoneFreePreceeding)
        {
            if (m_prev != nullptr)
                env().freeNode(m_prev->id());
        }
        if (flags & kMethcla_NodeDoneFreeFollowing)
        {
             if (m_next != nullptr)
                 env().freeNode(m_next->id());
        }
        if (flags & kMethcla_NodeDoneFreeSelf)
        {
            env().freeNode(id());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 - Mozy, Inc.

#include <boost/bind.hpp>

#include "mordor/atomic.h"
#include "mordor/fiber.h"
#include "mordor/fibersynchronization.h"
#include "mordor/iomanager.h"
#include "mordor/sleep.h"
#include "mordor/test/test.h"
#include "mordor/workerpool.h"

using namespace Mordor;

template<typename M> void test_mutex_basic()
{
    WorkerPool pool;
    M mutex;

    typename M::ScopedLock lock(mutex);
}

MORDOR_UNITTEST(FiberMutex, basic)
{
    test_mutex_basic<FiberMutex>();
}

template<typename M> inline void contentionFiber(int fiberNo, M &mutex, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, fiberNo);
    typename M::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, fiberNo + 3 + 1);
}

template<typename M> void test_mutex_contention()
{
    WorkerPool pool;
    M mutex;
    int sequence = 0;
    Fiber::ptr fiber1(new Fiber(NULL)), fiber2(new Fiber(NULL)),
        fiber3(new Fiber(NULL));
    fiber1->reset(boost::bind(&contentionFiber<M>, 1, boost::ref(mutex),
        boost::ref(sequence)));
    fiber2->reset(boost::bind(&contentionFiber<M>, 2, boost::ref(mutex),
        boost::ref(sequence)));
    fiber3->reset(boost::bind(&contentionFiber<M>, 3, boost::ref(mutex),
        boost::ref(sequence)));

    {
        typename M::ScopedLock lock(mutex);
        pool.schedule(fiber1);
        pool.schedule(fiber2);
        pool.schedule(fiber3);
        pool.dispatch();
        MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    }
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 8);
}

MORDOR_UNITTEST(FiberMutex, contention)
{
    test_mutex_contention<FiberMutex>();
}

#ifndef NDEBUG
MORDOR_UNITTEST(FiberMutex, notRecursive)
{
    WorkerPool pool;
    FiberMutex mutex;

    FiberMutex::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_ASSERTED(mutex.lock());
}
#endif

template<typename M> inline void lockIt(M &mutex)
{
    typename M::ScopedLock lock(mutex);
}

template<typename M> void test_mutex_unlockUnique()
{
    WorkerPool pool;
    M mutex;

    typename M::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT(!lock.unlockIfNotUnique());
    pool.schedule(boost::bind(&lockIt<M>, boost::ref(mutex)));
    Scheduler::yield();
    MORDOR_TEST_ASSERT(lock.unlockIfNotUnique());
    pool.dispatch();
}

MORDOR_UNITTEST(FiberMutex, unlockUnique)
{
    test_mutex_unlockUnique<FiberMutex>();
}

template<typename M> inline void lockAndHold(IOManager &ioManager, M &mutex, Atomic<int> &counter)
{
    --counter;
    typename M::ScopedLock lock(mutex);
    while(counter > 0)
        Mordor::sleep(ioManager, 50000); // sleep 50ms
}

template<typename M> void test_mutex_performance()
{
    IOManager ioManager(2, true);
    M mutex;
#ifdef X86_64
#ifndef NDEBUG_PERF
    int repeatness = 10000;
#else
    int repeatness = 50000;
#endif
#else
    // on a 32bit system, a process can only have a 4GB virtual address
    // each fiber wound take 1MB virtual address, this gives at most
    // 4096 fibers can be alive simultaneously.
    int repeatness = 1000;
#endif
    Atomic<int> counter = repeatness;
    unsigned long long before = TimerManager::now();
    for (int i=0; i<repeatness; ++i) {
        ioManager.schedule(boost::bind(lockAndHold<M>,
                                boost::ref(ioManager),
                                boost::ref(mutex),
                                boost::ref(counter)));
    }
    ioManager.stop();
    unsigned long long elapse = TimerManager::now() - before;
    MORDOR_LOG_INFO(Mordor::Log::root()) << "elapse: " << elapse;
}

MORDOR_UNITTEST(FiberMutex, mutexPerformance)
{
    test_mutex_performance<FiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, basic)
{
    test_mutex_basic<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, recursive_basic)
{
    WorkerPool pool;
    RecursiveFiberMutex mutex;

    RecursiveFiberMutex::ScopedLock lock0(mutex);
    {
        RecursiveFiberMutex::ScopedLock lock1(mutex);
        {
            RecursiveFiberMutex::ScopedLock lock2(mutex);
        }
    }
}

MORDOR_UNITTEST(RecursiveFiberMutex, contention)
{
    test_mutex_contention<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, mutexPerformance)
{
    test_mutex_performance<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, unlockUnique)
{
    test_mutex_unlockUnique<RecursiveFiberMutex>();
}

static void signalMe(FiberCondition &condition, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    condition.signal();
}

MORDOR_UNITTEST(FiberCondition, signal)
{
    int sequence = 0;
    WorkerPool pool;
    FiberMutex mutex;
    FiberCondition condition(mutex);

    FiberMutex::ScopedLock lock(mutex);
    pool.schedule(boost::bind(&signalMe, boost::ref(condition),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    condition.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
}

static void waitOnMe(FiberCondition &condition, FiberMutex &mutex,
                     int &sequence, int expected)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected * 2);
    FiberMutex::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected * 2 + 1);
    condition.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 8);
}

MORDOR_UNITTEST(FiberCondition, broadcast)
{
    int sequence = 0;
    WorkerPool pool;
    FiberMutex mutex;
    FiberCondition condition(mutex);

    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 1));
    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 2));
    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 3));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 8);
    condition.broadcast();
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 12);
}

static void signalMe2(FiberEvent &event, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    event.set();
}

MORDOR_UNITTEST(FiberEvent, autoReset)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event;

    pool.schedule(boost::bind(&signalMe2, boost::ref(event),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    event.set();
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}

MORDOR_UNITTEST(FiberEvent, manualReset)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event(false);

    pool.schedule(boost::bind(&signalMe2, boost::ref(event),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    // It's manual reset; you can wait as many times as you want until it's
    // reset
    event.wait();
    event.wait();
}

static void waitOnMe2(FiberEvent &event, int &sequence, int expected)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 5);
}

MORDOR_UNITTEST(FiberEvent, manualResetMultiple)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event(false);

    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 1));
    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 2));
    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 3));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
    event.set();
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 9);
    // It's manual reset; you can wait as many times as you want until it's
    // reset
    event.wait();
    event.wait();
}

class EventOwner
{
public:
    EventOwner()
        : m_event(false)
        , m_destroying(false)
    {}

    ~EventOwner()
    {

        // 1 thread case - we can't awake from yielding in the wait() call
        // until the fiber for the scheduled setEvent call is complete
        //
        // Multi-thread case - We can wake up because event is signalled, but
        //other thread might still be inside m_event.set() call,
        //with m_event mutex still locked.  Destroying that mutex while
        //set() is being called can cause crash
        m_event.wait();
        m_destroying = true;

        // Note: in debug mode the FiberEvent will get blocked waiting
        // for the lock help in FiberEvent::set, but NDEBUG build will not
    }

    void setEvent()
    {
        m_event.set();
        if (m_destroying) {
            MORDOR_NOTREACHED();
        }
    }

    FiberEvent m_event;
    bool m_destroying;
};

MORDOR_UNITTEST(FiberEvent, destroyAfterSet)
{
    // Demo risk of using an FiberEvent in multi-threaded enviroment
#if 0
    {
        //Not safe - owner destruction can start while pool2 is still
        //executing setEvent().  Even though we wait on event the
        //destructor is allowed to proceed before setEvent() has finished.
        WorkerPool pool;
        WorkerPool pool2(1,false);
        EventOwner owner;
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }
#endif

    {
        // Safe multi-threaded scenario - pool2 is stopped before event owner is destroyed
        // which ensures that scheduled event is complete
        WorkerPool pool;
        WorkerPool pool2(1,false);
        EventOwner owner;
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
        pool2.stop();
    }

    {
        // Safe multi-threaded scenario - variables are declared in correct order so
        // that pool2 is stopped before event owner is destroyed
        WorkerPool pool;
        EventOwner owner;
        WorkerPool pool2(1,false);
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

    {
        // Safe single threaded scenario - pool stops itself before
        // owner is destroyed
        WorkerPool pool;
        EventOwner owner;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
        pool.stop();
    }

    {
        // Safe single threaded scenario - pool destruction automatically
        // blocks until setEvent is complete, then owner is destroyed
        EventOwner owner;
        WorkerPool pool;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

    {
        // This is the only case that the event is actually needed and useful!
        // Because only one fiber executes at a time on the single thread
        WorkerPool pool;
        EventOwner owner;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

}
<commit_msg>add an unit test for FiberEvent<commit_after>// Copyright (c) 2009 - Mozy, Inc.

#include <boost/bind.hpp>

#include "mordor/atomic.h"
#include "mordor/fiber.h"
#include "mordor/fibersynchronization.h"
#include "mordor/iomanager.h"
#include "mordor/sleep.h"
#include "mordor/test/test.h"
#include "mordor/workerpool.h"

using namespace Mordor;

template<typename M> void test_mutex_basic()
{
    WorkerPool pool;
    M mutex;

    typename M::ScopedLock lock(mutex);
}

MORDOR_UNITTEST(FiberMutex, basic)
{
    test_mutex_basic<FiberMutex>();
}

template<typename M> inline void contentionFiber(int fiberNo, M &mutex, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, fiberNo);
    typename M::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, fiberNo + 3 + 1);
}

template<typename M> void test_mutex_contention()
{
    WorkerPool pool;
    M mutex;
    int sequence = 0;
    Fiber::ptr fiber1(new Fiber(NULL)), fiber2(new Fiber(NULL)),
        fiber3(new Fiber(NULL));
    fiber1->reset(boost::bind(&contentionFiber<M>, 1, boost::ref(mutex),
        boost::ref(sequence)));
    fiber2->reset(boost::bind(&contentionFiber<M>, 2, boost::ref(mutex),
        boost::ref(sequence)));
    fiber3->reset(boost::bind(&contentionFiber<M>, 3, boost::ref(mutex),
        boost::ref(sequence)));

    {
        typename M::ScopedLock lock(mutex);
        pool.schedule(fiber1);
        pool.schedule(fiber2);
        pool.schedule(fiber3);
        pool.dispatch();
        MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    }
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 8);
}

MORDOR_UNITTEST(FiberMutex, contention)
{
    test_mutex_contention<FiberMutex>();
}

#ifndef NDEBUG
MORDOR_UNITTEST(FiberMutex, notRecursive)
{
    WorkerPool pool;
    FiberMutex mutex;

    FiberMutex::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_ASSERTED(mutex.lock());
}
#endif

template<typename M> inline void lockIt(M &mutex)
{
    typename M::ScopedLock lock(mutex);
}

template<typename M> void test_mutex_unlockUnique()
{
    WorkerPool pool;
    M mutex;

    typename M::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT(!lock.unlockIfNotUnique());
    pool.schedule(boost::bind(&lockIt<M>, boost::ref(mutex)));
    Scheduler::yield();
    MORDOR_TEST_ASSERT(lock.unlockIfNotUnique());
    pool.dispatch();
}

MORDOR_UNITTEST(FiberMutex, unlockUnique)
{
    test_mutex_unlockUnique<FiberMutex>();
}

template<typename M> inline void lockAndHold(IOManager &ioManager, M &mutex, Atomic<int> &counter)
{
    --counter;
    typename M::ScopedLock lock(mutex);
    while(counter > 0)
        Mordor::sleep(ioManager, 50000); // sleep 50ms
}

template<typename M> void test_mutex_performance()
{
    IOManager ioManager(2, true);
    M mutex;
#ifdef X86_64
#ifndef NDEBUG_PERF
    int repeatness = 10000;
#else
    int repeatness = 50000;
#endif
#else
    // on a 32bit system, a process can only have a 4GB virtual address
    // each fiber wound take 1MB virtual address, this gives at most
    // 4096 fibers can be alive simultaneously.
    int repeatness = 1000;
#endif
    Atomic<int> counter = repeatness;
    unsigned long long before = TimerManager::now();
    for (int i=0; i<repeatness; ++i) {
        ioManager.schedule(boost::bind(lockAndHold<M>,
                                boost::ref(ioManager),
                                boost::ref(mutex),
                                boost::ref(counter)));
    }
    ioManager.stop();
    unsigned long long elapse = TimerManager::now() - before;
    MORDOR_LOG_INFO(Mordor::Log::root()) << "elapse: " << elapse;
}

MORDOR_UNITTEST(FiberMutex, mutexPerformance)
{
    test_mutex_performance<FiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, basic)
{
    test_mutex_basic<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, recursive_basic)
{
    WorkerPool pool;
    RecursiveFiberMutex mutex;

    RecursiveFiberMutex::ScopedLock lock0(mutex);
    {
        RecursiveFiberMutex::ScopedLock lock1(mutex);
        {
            RecursiveFiberMutex::ScopedLock lock2(mutex);
        }
    }
}

MORDOR_UNITTEST(RecursiveFiberMutex, contention)
{
    test_mutex_contention<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, mutexPerformance)
{
    test_mutex_performance<RecursiveFiberMutex>();
}

MORDOR_UNITTEST(RecursiveFiberMutex, unlockUnique)
{
    test_mutex_unlockUnique<RecursiveFiberMutex>();
}

static void signalMe(FiberCondition &condition, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    condition.signal();
}

MORDOR_UNITTEST(FiberCondition, signal)
{
    int sequence = 0;
    WorkerPool pool;
    FiberMutex mutex;
    FiberCondition condition(mutex);

    FiberMutex::ScopedLock lock(mutex);
    pool.schedule(boost::bind(&signalMe, boost::ref(condition),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    condition.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
}

static void waitOnMe(FiberCondition &condition, FiberMutex &mutex,
                     int &sequence, int expected)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected * 2);
    FiberMutex::ScopedLock lock(mutex);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected * 2 + 1);
    condition.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 8);
}

MORDOR_UNITTEST(FiberCondition, broadcast)
{
    int sequence = 0;
    WorkerPool pool;
    FiberMutex mutex;
    FiberCondition condition(mutex);

    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 1));
    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 2));
    pool.schedule(boost::bind(&waitOnMe, boost::ref(condition),
        boost::ref(mutex), boost::ref(sequence), 3));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 8);
    condition.broadcast();
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 12);
}

static void signalMe2(FiberEvent &event, int &sequence)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    event.set();
}

MORDOR_UNITTEST(FiberEvent, autoResetSetWithoutExistingWaiters)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event;

    pool.schedule(boost::bind(&signalMe2, boost::ref(event),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    event.set();
    // no fiber waiting at this moment, but the event is signaled
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}

static void signalMe3(TimerManager &manager, FiberEvent &event,
                      int &sequence, unsigned long long awhile)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    event.set();
    Mordor::sleep(manager, awhile);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    // a fiber is already waiting for a while
    event.set();
}

MORDOR_UNITTEST(FiberEvent, autoResetSetWithExistingWaiters)
{
    int sequence = 0;
    IOManager manager; // for a timer-enabled scheduler
    FiberEvent event;
    static const unsigned long long awhile = 50000ULL; // sleep for 50ms

    manager.schedule(boost::bind(&signalMe3, boost::ref(manager),
        boost::ref(event), boost::ref(sequence), awhile));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    Test::TakesAtLeast _(awhile);
    // the first set() call should not leave the event signaled, so this fiber
    // should be blocked until signalMe3() allows it to move on.
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
}

MORDOR_UNITTEST(FiberEvent, manualReset)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event(false);

    pool.schedule(boost::bind(&signalMe2, boost::ref(event),
        boost::ref(sequence)));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    // It's manual reset; you can wait as many times as you want until it's
    // reset
    event.wait();
    event.wait();
}

static void waitOnMe2(FiberEvent &event, int &sequence, int expected)
{
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 1);
    event.wait();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, expected + 5);
}

MORDOR_UNITTEST(FiberEvent, manualResetMultiple)
{
    int sequence = 0;
    WorkerPool pool;
    FiberEvent event(false);

    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 1));
    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 2));
    pool.schedule(boost::bind(&waitOnMe2, boost::ref(event),
        boost::ref(sequence), 3));
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
    event.set();
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 9);
    // It's manual reset; you can wait as many times as you want until it's
    // reset
    event.wait();
    event.wait();
}

class EventOwner
{
public:
    EventOwner()
        : m_event(false)
        , m_destroying(false)
    {}

    ~EventOwner()
    {

        // 1 thread case - we can't awake from yielding in the wait() call
        // until the fiber for the scheduled setEvent call is complete
        //
        // Multi-thread case - We can wake up because event is signalled, but
        //other thread might still be inside m_event.set() call,
        //with m_event mutex still locked.  Destroying that mutex while
        //set() is being called can cause crash
        m_event.wait();
        m_destroying = true;

        // Note: in debug mode the FiberEvent will get blocked waiting
        // for the lock help in FiberEvent::set, but NDEBUG build will not
    }

    void setEvent()
    {
        m_event.set();
        if (m_destroying) {
            MORDOR_NOTREACHED();
        }
    }

    FiberEvent m_event;
    bool m_destroying;
};

MORDOR_UNITTEST(FiberEvent, destroyAfterSet)
{
    // Demo risk of using an FiberEvent in multi-threaded enviroment
#if 0
    {
        //Not safe - owner destruction can start while pool2 is still
        //executing setEvent().  Even though we wait on event the
        //destructor is allowed to proceed before setEvent() has finished.
        WorkerPool pool;
        WorkerPool pool2(1,false);
        EventOwner owner;
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }
#endif

    {
        // Safe multi-threaded scenario - pool2 is stopped before event owner is destroyed
        // which ensures that scheduled event is complete
        WorkerPool pool;
        WorkerPool pool2(1,false);
        EventOwner owner;
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
        pool2.stop();
    }

    {
        // Safe multi-threaded scenario - variables are declared in correct order so
        // that pool2 is stopped before event owner is destroyed
        WorkerPool pool;
        EventOwner owner;
        WorkerPool pool2(1,false);
        pool2.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

    {
        // Safe single threaded scenario - pool stops itself before
        // owner is destroyed
        WorkerPool pool;
        EventOwner owner;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
        pool.stop();
    }

    {
        // Safe single threaded scenario - pool destruction automatically
        // blocks until setEvent is complete, then owner is destroyed
        EventOwner owner;
        WorkerPool pool;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

    {
        // This is the only case that the event is actually needed and useful!
        // Because only one fiber executes at a time on the single thread
        WorkerPool pool;
        EventOwner owner;
        pool.schedule(boost::bind(&EventOwner::setEvent, &owner));
    }

}
<|endoftext|>