<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "auth/AuthSupported.h"
#include "auth/KeyRing.h"
#include "common/safe_io.h"
#include "config.h"
#include "common/common_init.h"
#include "common/errno.h"
#include "common/signal.h"
#include "include/color.h"

/* Set foreground logging
 *
 * Forces the process to log only to stderr, overriding whatever was in the ceph.conf.
 *
 * TODO: make this configurable by a command line switch or environment variable, if users want
 * an unusual logging setup for their foreground process.
 */
void set_foreground_logging()
{
  free((void*)g_conf.log_file);
  g_conf.log_file = NULL;

  free((void*)g_conf.log_dir);
  g_conf.log_dir = NULL;

  free((void*)g_conf.log_sym_dir);
  g_conf.log_sym_dir = NULL;

  g_conf.log_sym_history = 0;

  g_conf.log_to_stderr = LOG_TO_STDERR_ALL;

  g_conf.log_to_syslog = false;

  g_conf.log_per_instance = false;

  g_conf.log_to_file = false;
}

void common_set_defaults(bool daemon)
{
  if (daemon) {
    cout << TEXT_YELLOW << " ** WARNING: Ceph is still under heavy development, and is only suitable for **" << TEXT_NORMAL << std::endl;
    cout << TEXT_YELLOW <<  " **          testing and review.  Do not trust it with important data.       **" << TEXT_NORMAL << std::endl;

    g_conf.daemonize = true;
  } else {
    g_conf.pid_file = 0;
  }
}

static void keyring_init(const char *filesearch)
{
  const char *filename = filesearch;
  string keyring_search = g_conf.keyring;
  string new_keyring;
  if (ceph_resolve_file_search(keyring_search, new_keyring)) {
    filename = new_keyring.c_str();
  }

  int ret = g_keyring.load(filename);
  if (ret) {
    derr << "keyring_init: failed to load " << filename << dendl;
    return;
  }

  if (g_conf.key && g_conf.key[0]) {
    string k = g_conf.key;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);
  } else if (g_conf.keyfile && g_conf.keyfile[0]) {
    char buf[100];
    int fd = ::open(g_conf.keyfile, O_RDONLY);
    if (fd < 0) {
      int err = errno;
      derr << "unable to open " << g_conf.keyfile << ": "
	   << cpp_strerror(err) << dendl;
      ceph_abort();
    }
    memset(buf, 0, sizeof(buf));
    int len = safe_read(fd, buf, sizeof(buf) - 1);
    if (len < 0) {
      derr << "unable to read key from " << g_conf.keyfile << ": "
	   << cpp_strerror(len) << dendl;
      TEMP_FAILURE_RETRY(::close(fd));
      ceph_abort();
    }
    TEMP_FAILURE_RETRY(::close(fd));

    buf[len] = 0;
    string k = buf;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);
  }
}

void common_init(std::vector<const char*>& args, const char *module_type, int flags)
{
  parse_startup_config_options(args, module_type, flags);
  parse_config_options(args);
  install_standard_sighandlers();

#ifdef HAVE_LIBTCMALLOC
  if (g_conf.tcmalloc_profiler_run && g_conf.tcmalloc_have) {
    char profile_name[PATH_MAX];
    sprintf(profile_name, "%s/%s", g_conf.log_dir, g_conf.name);
    char *val = new char[sizeof(int)*8+1];
    sprintf(val, "%i", g_conf.profiler_allocation_interval);
    setenv("HEAP_PROFILE_ALLOCATION_INTERVAL", val, g_conf.profiler_allocation_interval);
    sprintf(val, "%i", g_conf.profiler_highwater_interval);
    setenv("HEAP_PROFILE_INUSE_INTERVAL", val, g_conf.profiler_highwater_interval);
    generic_dout(0) << "turning on heap profiler with prefix " << profile_name << dendl;
    g_conf.profiler_start(profile_name);
  }
#endif //HAVE_LIBTCMALLOC

  if (flags & STARTUP_FLAG_INIT_KEYS)  {
    if (is_supported_auth(CEPH_AUTH_CEPHX))
      keyring_init(g_conf.keyring);
  }
}

<commit_msg>keyring_init: don't print error when explicit key/keyfile is specified<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "auth/AuthSupported.h"
#include "auth/KeyRing.h"
#include "common/safe_io.h"
#include "config.h"
#include "common/common_init.h"
#include "common/errno.h"
#include "common/signal.h"
#include "include/color.h"

/* Set foreground logging
 *
 * Forces the process to log only to stderr, overriding whatever was in the ceph.conf.
 *
 * TODO: make this configurable by a command line switch or environment variable, if users want
 * an unusual logging setup for their foreground process.
 */
void set_foreground_logging()
{
  free((void*)g_conf.log_file);
  g_conf.log_file = NULL;

  free((void*)g_conf.log_dir);
  g_conf.log_dir = NULL;

  free((void*)g_conf.log_sym_dir);
  g_conf.log_sym_dir = NULL;

  g_conf.log_sym_history = 0;

  g_conf.log_to_stderr = LOG_TO_STDERR_ALL;

  g_conf.log_to_syslog = false;

  g_conf.log_per_instance = false;

  g_conf.log_to_file = false;
}

void common_set_defaults(bool daemon)
{
  if (daemon) {
    cout << TEXT_YELLOW << " ** WARNING: Ceph is still under heavy development, and is only suitable for **" << TEXT_NORMAL << std::endl;
    cout << TEXT_YELLOW <<  " **          testing and review.  Do not trust it with important data.       **" << TEXT_NORMAL << std::endl;

    g_conf.daemonize = true;
  } else {
    g_conf.pid_file = 0;
  }
}

static void keyring_init(const char *filesearch)
{
  const char *filename = filesearch;
  string keyring_search = g_conf.keyring;
  string new_keyring;
  if (ceph_resolve_file_search(keyring_search, new_keyring)) {
    filename = new_keyring.c_str();
  }

  int ret = g_keyring.load(filename);

  if (g_conf.key && g_conf.key[0]) {
    string k = g_conf.key;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  } else if (g_conf.keyfile && g_conf.keyfile[0]) {
    char buf[100];
    int fd = ::open(g_conf.keyfile, O_RDONLY);
    if (fd < 0) {
      int err = errno;
      derr << "unable to open " << g_conf.keyfile << ": "
	   << cpp_strerror(err) << dendl;
      ceph_abort();
    }
    memset(buf, 0, sizeof(buf));
    int len = safe_read(fd, buf, sizeof(buf) - 1);
    if (len < 0) {
      derr << "unable to read key from " << g_conf.keyfile << ": "
	   << cpp_strerror(len) << dendl;
      TEMP_FAILURE_RETRY(::close(fd));
      ceph_abort();
    }
    TEMP_FAILURE_RETRY(::close(fd));

    buf[len] = 0;
    string k = buf;
    EntityAuth ea;
    ea.key.decode_base64(k);
    g_keyring.add(*g_conf.entity_name, ea);

    ret = 0;
  }

  if (ret) {
    derr << "keyring_init: failed to load " << filename << dendl;
    return;
  }
}

void common_init(std::vector<const char*>& args, const char *module_type, int flags)
{
  parse_startup_config_options(args, module_type, flags);
  parse_config_options(args);
  install_standard_sighandlers();

#ifdef HAVE_LIBTCMALLOC
  if (g_conf.tcmalloc_profiler_run && g_conf.tcmalloc_have) {
    char profile_name[PATH_MAX];
    sprintf(profile_name, "%s/%s", g_conf.log_dir, g_conf.name);
    char *val = new char[sizeof(int)*8+1];
    sprintf(val, "%i", g_conf.profiler_allocation_interval);
    setenv("HEAP_PROFILE_ALLOCATION_INTERVAL", val, g_conf.profiler_allocation_interval);
    sprintf(val, "%i", g_conf.profiler_highwater_interval);
    setenv("HEAP_PROFILE_INUSE_INTERVAL", val, g_conf.profiler_highwater_interval);
    generic_dout(0) << "turning on heap profiler with prefix " << profile_name << dendl;
    g_conf.profiler_start(profile_name);
  }
#endif //HAVE_LIBTCMALLOC

  if (flags & STARTUP_FLAG_INIT_KEYS)  {
    if (is_supported_auth(CEPH_AUTH_CEPHX))
      keyring_init(g_conf.keyring);
  }
}

<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2003 by                                                 *
 *   Unai Garro (ugarro@users.sourceforge.net)                             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "ingredientmatcherdialog.h"

#include "datablocks/recipelist.h"
#include "elementlist.h"
#include "DBBackend/recipedb.h"
#include "widgets/krelistview.h"

#include <qpainter.h>
#include <qstringlist.h>
#include <kiconloader.h>
#include <klocale.h>

IngredientMatcherDialog::IngredientMatcherDialog(QWidget *parent,RecipeDB *db):QVBox(parent)
{
	// Initialize internal variables
	database=db;

	//Design the dialog
	setSpacing(10);

		// Ingredient list
	ingredientListView=new KreListView(this,i18n("Ingredients"),true,1);
	ingredientListView->listView()->setAllColumnsShowFocus(true);
	ingredientListView->listView()->addColumn("*");
	ingredientListView->listView()->addColumn(i18n("Ingredient"));
		// Box to select allowed number of missing ingredients
	missingBox=new QHBox(this);
	missingNumberLabel=new QLabel(missingBox);
	missingNumberLabel->setText(i18n("Missing ingredients allowed:"));
	missingNumberCombo=new KComboBox(missingBox);
	QStringList optionsList;
	optionsList.append("1");
	optionsList+="2";
	optionsList+="3";
	optionsList+=i18n("any");
	missingNumberCombo->insertStringList(optionsList);

		// Found recipe list
	recipeListView=new KreListView(this,i18n("Matching Recipes"),false,1,missingBox);
	recipeListView->listView()->setAllColumnsShowFocus(true);
	recipeListView->listView()->addColumn(i18n("Title"));
	recipeListView->listView()->addColumn(i18n("Missing Ingredients"));
	recipeListView->listView()->setSorting(-1);

	KIconLoader il;
	QHBox *buttonBox=new QHBox(this);

	okButton=new QPushButton(buttonBox);
	okButton->setIconSet(il.loadIconSet("button_ok", KIcon::Small));
	okButton->setText(i18n("Find matching recipes"));

	clearButton=new QPushButton(buttonBox);
	clearButton->setIconSet(il.loadIconSet("editclear", KIcon::Small));
	clearButton->setText(i18n("Clear recipe list"));

	// Load the data
	reloadIngredients();

	// Connect signals & slots
	connect (okButton,SIGNAL(clicked()), this,SLOT(findRecipes()));
	connect (clearButton,SIGNAL(clicked()),recipeListView->listView(),SLOT(clear()));

}

IngredientMatcherDialog::~IngredientMatcherDialog()
{

}

void IngredientMatcherDialog::findRecipes(void)
{
	RecipeList rlist;
	IngredientList ilist;
	database->loadRecipeDetails(&rlist,true,false);

	QListViewItem *qlv_it;

	// First make a list of the ingredients that we have
	for (qlv_it=ingredientListView->listView()->firstChild();qlv_it;qlv_it=qlv_it->nextSibling())
		{
		IngredientListItem *il_it=(IngredientListItem*) qlv_it;
		if (il_it->isOn())
			{
			Ingredient ing; ing.name=il_it->name(); ing.ingredientID=il_it->id();
			ilist.append(ing);
			}
		}

	// Clear the list
	recipeListView->listView()->clear();
	// Add the section header
	new SectionItem(recipeListView->listView(),i18n("Possible recipes with the specified ingredients"));

	// Now show the recipes with ingredients that are contained in the previous set
	// of ingredients
	RecipeList incompleteRecipes;
	QValueList <int> missingNumbers;

	RecipeList::Iterator it;
	for (it=rlist.begin();it!=rlist.end();++it)
		{
		IngredientList il=(*it).ingList;
		IngredientList missing;
		if (ilist.containsSubSet(il,missing))
			{
			new RecipeListItem(recipeListView->listView(),*it);
			}
		else incompleteRecipes.append(*it);
		missingNumbers.append(missing.count());
		}

	// Show recipes with missing ingredients
	new SectionItem(recipeListView->listView(),i18n("You are missing some ingredients for:"));

	QValueList<int>::Iterator nit;
	if (this->missingNumberCombo->currentItem()==3) // Any
	{
		for (it=incompleteRecipes.begin();it!=incompleteRecipes.end();++it)
		{
			new RecipeListItem(recipeListView->listView(),*it);
		}
	}
	else // 1..3
	{
		int missingNoAllowed=missingNumberCombo->currentText().toInt();
		nit=missingNumbers.begin();
		for (it=incompleteRecipes.begin();it!=incompleteRecipes.end();++it,++nit)
		{
			if ((*nit)<=missingNoAllowed)
				new RecipeListItem(recipeListView->listView(),*it);
		}
	}
}

void IngredientMatcherDialog::reloadIngredients(void)
{

	ingredientListView->listView()->clear();
	ElementList ingredientList;
	database->loadIngredients(&ingredientList);

	ElementList::Iterator it;

	for (it=ingredientList.begin();it!=ingredientList.end();++it)
		{
		Element ingredient=*it;
		new IngredientListItem(ingredientListView->listView(),ingredient);
		}
}

void SectionItem::paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align )
{
int totalWidth=listView()->columnWidth(0)+listView()->columnWidth(1);

QPixmap sectionPm(totalWidth,height()); QPainter painter(&sectionPm);

// Draw the section's deco
painter.setPen(KGlobalSettings::activeTitleColor());
painter.setBrush(KGlobalSettings::activeTitleColor());
painter.drawRect(0,0,totalWidth,height());

// Draw the section's text

QFont titleFont=KGlobalSettings::windowTitleFont ();
painter.setFont(titleFont);

painter.setPen(KGlobalSettings::activeTextColor());
painter.drawText(0,0,totalWidth,height(),Qt::AlignHCenter|Qt::AlignVCenter,mText);

// Paint only this cell (causes trouble while resizing)

/*if (column==0) bitBlt(p->device(), 0, 0, &textPm,0,0,width,height());
else if (column==1) bitBlt(p->device(),listView()->columnWidth(0),0,&textPm,listView()->columnWidth(0),0,width,height());*/

// Paint full row
bitBlt(p->device(), 0, itemPos(), &sectionPm,0,0,totalWidth,height());

}<commit_msg>Add one more "None" option to the combo to display no recipes missing ingredients<commit_after>/***************************************************************************
 *   Copyright (C) 2003 by                                                 *
 *   Unai Garro (ugarro@users.sourceforge.net)                             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "ingredientmatcherdialog.h"

#include "datablocks/recipelist.h"
#include "elementlist.h"
#include "DBBackend/recipedb.h"
#include "widgets/krelistview.h"

#include <qpainter.h>
#include <qstringlist.h>
#include <kiconloader.h>
#include <klocale.h>

IngredientMatcherDialog::IngredientMatcherDialog(QWidget *parent,RecipeDB *db):QVBox(parent)
{
	// Initialize internal variables
	database=db;

	//Design the dialog
	setSpacing(10);

		// Ingredient list
	ingredientListView=new KreListView(this,i18n("Ingredients"),true,1);
	ingredientListView->listView()->setAllColumnsShowFocus(true);
	ingredientListView->listView()->addColumn("*");
	ingredientListView->listView()->addColumn(i18n("Ingredient"));
		// Box to select allowed number of missing ingredients
	missingBox=new QHBox(this);
	missingNumberLabel=new QLabel(missingBox);
	missingNumberLabel->setText(i18n("Missing ingredients allowed:"));
	missingNumberCombo=new KComboBox(missingBox);
	QStringList optionsList;
	optionsList.append(i18n("None"));
	optionsList+="1";
	optionsList+="2";
	optionsList+="3";
	optionsList+=i18n("any");
	missingNumberCombo->insertStringList(optionsList);

		// Found recipe list
	recipeListView=new KreListView(this,i18n("Matching Recipes"),false,1,missingBox);
	recipeListView->listView()->setAllColumnsShowFocus(true);
	recipeListView->listView()->addColumn(i18n("Title"));
	recipeListView->listView()->addColumn(i18n("Missing Ingredients"));
	recipeListView->listView()->setSorting(-1);

	KIconLoader il;
	QHBox *buttonBox=new QHBox(this);

	okButton=new QPushButton(buttonBox);
	okButton->setIconSet(il.loadIconSet("button_ok", KIcon::Small));
	okButton->setText(i18n("Find matching recipes"));

	clearButton=new QPushButton(buttonBox);
	clearButton->setIconSet(il.loadIconSet("editclear", KIcon::Small));
	clearButton->setText(i18n("Clear recipe list"));

	// Load the data
	reloadIngredients();

	// Connect signals & slots
	connect (okButton,SIGNAL(clicked()), this,SLOT(findRecipes()));
	connect (clearButton,SIGNAL(clicked()),recipeListView->listView(),SLOT(clear()));

}

IngredientMatcherDialog::~IngredientMatcherDialog()
{

}

void IngredientMatcherDialog::findRecipes(void)
{
	RecipeList rlist;
	IngredientList ilist;
	database->loadRecipeDetails(&rlist,true,false);

	QListViewItem *qlv_it;

	// First make a list of the ingredients that we have
	for (qlv_it=ingredientListView->listView()->firstChild();qlv_it;qlv_it=qlv_it->nextSibling())
		{
		IngredientListItem *il_it=(IngredientListItem*) qlv_it;
		if (il_it->isOn())
			{
			Ingredient ing; ing.name=il_it->name(); ing.ingredientID=il_it->id();
			ilist.append(ing);
			}
		}

	// Clear the list
	recipeListView->listView()->clear();
	// Add the section header
	new SectionItem(recipeListView->listView(),i18n("Possible recipes with the specified ingredients"));

	// Now show the recipes with ingredients that are contained in the previous set
	// of ingredients
	RecipeList incompleteRecipes;
	QValueList <int> missingNumbers;

	RecipeList::Iterator it;
	for (it=rlist.begin();it!=rlist.end();++it)
		{
		IngredientList il=(*it).ingList;
		IngredientList missing;
		if (ilist.containsSubSet(il,missing))
			{
			new RecipeListItem(recipeListView->listView(),*it);
			}
		else incompleteRecipes.append(*it);
		missingNumbers.append(missing.count());
		}

	//Check if the user wants to show missing ingredients

	if (this->missingNumberCombo->currentItem()==0) return; //None

	// Show recipes with missing ingredients
	new SectionItem(recipeListView->listView(),i18n("You are missing some ingredients for:"));

	QValueList<int>::Iterator nit;

	if (this->missingNumberCombo->currentItem()==4) // Any
	{
		for (it=incompleteRecipes.begin();it!=incompleteRecipes.end();++it)
		{
			new RecipeListItem(recipeListView->listView(),*it);
		}
	}
	else // 1..3
	{
		int missingNoAllowed=missingNumberCombo->currentText().toInt();
		nit=missingNumbers.begin();
		for (it=incompleteRecipes.begin();it!=incompleteRecipes.end();++it,++nit)
		{
			if ((*nit)<=missingNoAllowed)
				new RecipeListItem(recipeListView->listView(),*it);
		}
	}
}

void IngredientMatcherDialog::reloadIngredients(void)
{

	ingredientListView->listView()->clear();
	ElementList ingredientList;
	database->loadIngredients(&ingredientList);

	ElementList::Iterator it;

	for (it=ingredientList.begin();it!=ingredientList.end();++it)
		{
		Element ingredient=*it;
		new IngredientListItem(ingredientListView->listView(),ingredient);
		}
}

void SectionItem::paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align )
{
int totalWidth=listView()->columnWidth(0)+listView()->columnWidth(1);

QPixmap sectionPm(totalWidth,height()); QPainter painter(&sectionPm);

// Draw the section's deco
painter.setPen(KGlobalSettings::activeTitleColor());
painter.setBrush(KGlobalSettings::activeTitleColor());
painter.drawRect(0,0,totalWidth,height());

// Draw the section's text

QFont titleFont=KGlobalSettings::windowTitleFont ();
painter.setFont(titleFont);

painter.setPen(KGlobalSettings::activeTextColor());
painter.drawText(0,0,totalWidth,height(),Qt::AlignHCenter|Qt::AlignVCenter,mText);

// Paint only this cell (causes trouble while resizing)

/*if (column==0) bitBlt(p->device(), 0, 0, &textPm,0,0,width,height());
else if (column==1) bitBlt(p->device(),listView()->columnWidth(0),0,&textPm,listView()->columnWidth(0),0,width,height());*/

// Paint full row
bitBlt(p->device(), 0, itemPos(), &sectionPm,0,0,totalWidth,height());

}<|endoftext|>


<commit_before>//
//
// Copyright 2016 gRPC authors.
//
// 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 <grpc/support/port_platform.h>

#include "src/core/ext/filters/client_channel/subchannel_index.h"

#include <stdbool.h>
#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>

#include "src/core/lib/avl/avl.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/tls.h"

// a map of subchannel_key --> subchannel, used for detecting connections
// to the same destination in order to share them
static grpc_avl g_subchannel_index;

static gpr_mu g_mu;

static gpr_refcount g_refcount;

struct grpc_subchannel_key {
  grpc_subchannel_args args;
};

static bool g_force_creation = false;

static grpc_subchannel_key* create_key(
    const grpc_subchannel_args* args,
    grpc_channel_args* (*copy_channel_args)(const grpc_channel_args* args)) {
  grpc_subchannel_key* k =
      static_cast<grpc_subchannel_key*>(gpr_malloc(sizeof(*k)));
  k->args.filter_count = args->filter_count;
  if (k->args.filter_count > 0) {
    k->args.filters = static_cast<const grpc_channel_filter**>(
        gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count));
    memcpy(reinterpret_cast<grpc_channel_filter*>(k->args.filters),
           args->filters, sizeof(*k->args.filters) * k->args.filter_count);
  } else {
    k->args.filters = nullptr;
  }
  k->args.args = copy_channel_args(args->args);
  return k;
}

grpc_subchannel_key* grpc_subchannel_key_create(
    const grpc_subchannel_args* args) {
  return create_key(args, grpc_channel_args_normalize);
}

static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) {
  return create_key(&k->args, grpc_channel_args_copy);
}

int grpc_subchannel_key_compare(const grpc_subchannel_key* a,
                                const grpc_subchannel_key* b) {
  // To pretend the keys are different, return a non-zero value.
  if (GPR_UNLIKELY(g_force_creation)) return 1;
  int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
  if (c != 0) return c;
  if (a->args.filter_count > 0) {
    c = memcmp(a->args.filters, b->args.filters,
               a->args.filter_count * sizeof(*a->args.filters));
    if (c != 0) return c;
  }
  return grpc_channel_args_compare(a->args.args, b->args.args);
}

void grpc_subchannel_key_destroy(grpc_subchannel_key* k) {
  gpr_free(reinterpret_cast<grpc_channel_args*>(k->args.filters));
  grpc_channel_args_destroy(const_cast<grpc_channel_args*>(k->args.args));
  gpr_free(k);
}

static void sck_avl_destroy(void* p, void* user_data) {
  grpc_subchannel_key_destroy(static_cast<grpc_subchannel_key*>(p));
}

static void* sck_avl_copy(void* p, void* unused) {
  return subchannel_key_copy(static_cast<grpc_subchannel_key*>(p));
}

static long sck_avl_compare(void* a, void* b, void* unused) {
  return grpc_subchannel_key_compare(static_cast<grpc_subchannel_key*>(a),
                                     static_cast<grpc_subchannel_key*>(b));
}

static void scv_avl_destroy(void* p, void* user_data) {
  GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "subchannel_index");
}

static void* scv_avl_copy(void* p, void* unused) {
  GRPC_SUBCHANNEL_WEAK_REF((grpc_subchannel*)p, "subchannel_index");
  return p;
}

static const grpc_avl_vtable subchannel_avl_vtable = {
    sck_avl_destroy,  // destroy_key
    sck_avl_copy,     // copy_key
    sck_avl_compare,  // compare_keys
    scv_avl_destroy,  // destroy_value
    scv_avl_copy      // copy_value
};

void grpc_subchannel_index_init(void) {
  g_subchannel_index = grpc_avl_create(&subchannel_avl_vtable);
  gpr_mu_init(&g_mu);
  gpr_ref_init(&g_refcount, 1);
}

void grpc_subchannel_index_shutdown(void) {
  // TODO(juanlishen): This refcounting mechanism may lead to memory leackage.
  // To solve that, we should force polling to flush any pending callbacks, then
  // shutdown safely.
  grpc_subchannel_index_unref();
}

void grpc_subchannel_index_unref(void) {
  if (gpr_unref(&g_refcount)) {
    gpr_mu_destroy(&g_mu);
    grpc_avl_unref(g_subchannel_index, grpc_core::ExecCtx::Get());
  }
}

void grpc_subchannel_index_ref(void) { gpr_ref_non_zero(&g_refcount); }

grpc_subchannel* grpc_subchannel_index_find(grpc_subchannel_key* key) {
  // Lock, and take a reference to the subchannel index.
  // We don't need to do the search under a lock as avl's are immutable.
  gpr_mu_lock(&g_mu);
  grpc_avl index = grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
  gpr_mu_unlock(&g_mu);

  grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
      (grpc_subchannel*)grpc_avl_get(index, key, grpc_core::ExecCtx::Get()),
      "index_find");
  grpc_avl_unref(index, grpc_core::ExecCtx::Get());

  return c;
}

grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key,
                                                grpc_subchannel* constructed) {
  grpc_subchannel* c = nullptr;
  bool need_to_unref_constructed = false;

  while (c == nullptr) {
    need_to_unref_constructed = false;

    // Compare and swap loop:
    // - take a reference to the current index
    gpr_mu_lock(&g_mu);
    grpc_avl index =
        grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
    gpr_mu_unlock(&g_mu);

    // - Check to see if a subchannel already exists
    c = static_cast<grpc_subchannel*>(
        grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
    if (c != nullptr) {
      c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
    }
    if (c != nullptr) {
      // yes -> we're done
      need_to_unref_constructed = true;
    } else {
      // no -> update the avl and compare/swap
      grpc_avl updated =
          grpc_avl_add(grpc_avl_ref(index, grpc_core::ExecCtx::Get()),
                       subchannel_key_copy(key),
                       GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"),
                       grpc_core::ExecCtx::Get());

      // it may happen (but it's expected to be unlikely)
      // that some other thread has changed the index:
      // compare/swap here to check that, and retry as necessary
      gpr_mu_lock(&g_mu);
      if (index.root == g_subchannel_index.root) {
        GPR_SWAP(grpc_avl, updated, g_subchannel_index);
        c = constructed;
      }
      gpr_mu_unlock(&g_mu);

      grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
    }
    grpc_avl_unref(index, grpc_core::ExecCtx::Get());
  }

  if (need_to_unref_constructed) {
    GRPC_SUBCHANNEL_UNREF(constructed, "index_register");
  }

  return c;
}

void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
                                      grpc_subchannel* constructed) {
  bool done = false;
  while (!done) {
    // Compare and swap loop:
    // - take a reference to the current index
    gpr_mu_lock(&g_mu);
    grpc_avl index =
        grpc_avl_ref(g_subchannel_index, grpc_core::ExecCtx::Get());
    gpr_mu_unlock(&g_mu);

    // Check to see if this key still refers to the previously
    // registered subchannel
    grpc_subchannel* c = static_cast<grpc_subchannel*>(
        grpc_avl_get(index, key, grpc_core::ExecCtx::Get()));
    if (c != constructed) {
      grpc_avl_unref(index, grpc_core::ExecCtx::Get());
      break;
    }

    // compare and swap the update (some other thread may have
    // mutated the index behind us)
    grpc_avl updated =
        grpc_avl_remove(grpc_avl_ref(index, grpc_core::ExecCtx::Get()), key,
                        grpc_core::ExecCtx::Get());

    gpr_mu_lock(&g_mu);
    if (index.root == g_subchannel_index.root) {
      GPR_SWAP(grpc_avl, updated, g_subchannel_index);
      done = true;
    }
    gpr_mu_unlock(&g_mu);

    grpc_avl_unref(updated, grpc_core::ExecCtx::Get());
    grpc_avl_unref(index, grpc_core::ExecCtx::Get());
  }
}

void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {
  g_force_creation = force_creation;
}
<commit_msg>Stop passing ExecCtx as avl user_data.<commit_after>//
//
// Copyright 2016 gRPC authors.
//
// 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 <grpc/support/port_platform.h>

#include "src/core/ext/filters/client_channel/subchannel_index.h"

#include <stdbool.h>
#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>

#include "src/core/lib/avl/avl.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/tls.h"

// a map of subchannel_key --> subchannel, used for detecting connections
// to the same destination in order to share them
static grpc_avl g_subchannel_index;

static gpr_mu g_mu;

static gpr_refcount g_refcount;

struct grpc_subchannel_key {
  grpc_subchannel_args args;
};

static bool g_force_creation = false;

static grpc_subchannel_key* create_key(
    const grpc_subchannel_args* args,
    grpc_channel_args* (*copy_channel_args)(const grpc_channel_args* args)) {
  grpc_subchannel_key* k =
      static_cast<grpc_subchannel_key*>(gpr_malloc(sizeof(*k)));
  k->args.filter_count = args->filter_count;
  if (k->args.filter_count > 0) {
    k->args.filters = static_cast<const grpc_channel_filter**>(
        gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count));
    memcpy(reinterpret_cast<grpc_channel_filter*>(k->args.filters),
           args->filters, sizeof(*k->args.filters) * k->args.filter_count);
  } else {
    k->args.filters = nullptr;
  }
  k->args.args = copy_channel_args(args->args);
  return k;
}

grpc_subchannel_key* grpc_subchannel_key_create(
    const grpc_subchannel_args* args) {
  return create_key(args, grpc_channel_args_normalize);
}

static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) {
  return create_key(&k->args, grpc_channel_args_copy);
}

int grpc_subchannel_key_compare(const grpc_subchannel_key* a,
                                const grpc_subchannel_key* b) {
  // To pretend the keys are different, return a non-zero value.
  if (GPR_UNLIKELY(g_force_creation)) return 1;
  int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
  if (c != 0) return c;
  if (a->args.filter_count > 0) {
    c = memcmp(a->args.filters, b->args.filters,
               a->args.filter_count * sizeof(*a->args.filters));
    if (c != 0) return c;
  }
  return grpc_channel_args_compare(a->args.args, b->args.args);
}

void grpc_subchannel_key_destroy(grpc_subchannel_key* k) {
  gpr_free(reinterpret_cast<grpc_channel_args*>(k->args.filters));
  grpc_channel_args_destroy(const_cast<grpc_channel_args*>(k->args.args));
  gpr_free(k);
}

static void sck_avl_destroy(void* p, void* unused) {
  grpc_subchannel_key_destroy(static_cast<grpc_subchannel_key*>(p));
}

static void* sck_avl_copy(void* p, void* unused) {
  return subchannel_key_copy(static_cast<grpc_subchannel_key*>(p));
}

static long sck_avl_compare(void* a, void* b, void* unused) {
  return grpc_subchannel_key_compare(static_cast<grpc_subchannel_key*>(a),
                                     static_cast<grpc_subchannel_key*>(b));
}

static void scv_avl_destroy(void* p, void* unused) {
  GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "subchannel_index");
}

static void* scv_avl_copy(void* p, void* unused) {
  GRPC_SUBCHANNEL_WEAK_REF((grpc_subchannel*)p, "subchannel_index");
  return p;
}

static const grpc_avl_vtable subchannel_avl_vtable = {
    sck_avl_destroy,  // destroy_key
    sck_avl_copy,     // copy_key
    sck_avl_compare,  // compare_keys
    scv_avl_destroy,  // destroy_value
    scv_avl_copy      // copy_value
};

void grpc_subchannel_index_init(void) {
  g_subchannel_index = grpc_avl_create(&subchannel_avl_vtable);
  gpr_mu_init(&g_mu);
  gpr_ref_init(&g_refcount, 1);
}

void grpc_subchannel_index_shutdown(void) {
  // TODO(juanlishen): This refcounting mechanism may lead to memory leackage.
  // To solve that, we should force polling to flush any pending callbacks, then
  // shutdown safely.
  grpc_subchannel_index_unref();
}

void grpc_subchannel_index_unref(void) {
  if (gpr_unref(&g_refcount)) {
    gpr_mu_destroy(&g_mu);
    grpc_avl_unref(g_subchannel_index, nullptr);
  }
}

void grpc_subchannel_index_ref(void) { gpr_ref_non_zero(&g_refcount); }

grpc_subchannel* grpc_subchannel_index_find(grpc_subchannel_key* key) {
  // Lock, and take a reference to the subchannel index.
  // We don't need to do the search under a lock as avl's are immutable.
  gpr_mu_lock(&g_mu);
  grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
  gpr_mu_unlock(&g_mu);

  grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
      (grpc_subchannel*)grpc_avl_get(index, key, nullptr), "index_find");
  grpc_avl_unref(index, nullptr);

  return c;
}

grpc_subchannel* grpc_subchannel_index_register(grpc_subchannel_key* key,
                                                grpc_subchannel* constructed) {
  grpc_subchannel* c = nullptr;
  bool need_to_unref_constructed = false;

  while (c == nullptr) {
    need_to_unref_constructed = false;

    // Compare and swap loop:
    // - take a reference to the current index
    gpr_mu_lock(&g_mu);
    grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
    gpr_mu_unlock(&g_mu);

    // - Check to see if a subchannel already exists
    c = static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr));
    if (c != nullptr) {
      c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
    }
    if (c != nullptr) {
      // yes -> we're done
      need_to_unref_constructed = true;
    } else {
      // no -> update the avl and compare/swap
      grpc_avl updated = grpc_avl_add(
          grpc_avl_ref(index, nullptr), subchannel_key_copy(key),
          GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), nullptr);

      // it may happen (but it's expected to be unlikely)
      // that some other thread has changed the index:
      // compare/swap here to check that, and retry as necessary
      gpr_mu_lock(&g_mu);
      if (index.root == g_subchannel_index.root) {
        GPR_SWAP(grpc_avl, updated, g_subchannel_index);
        c = constructed;
      }
      gpr_mu_unlock(&g_mu);

      grpc_avl_unref(updated, nullptr);
    }
    grpc_avl_unref(index, nullptr);
  }

  if (need_to_unref_constructed) {
    GRPC_SUBCHANNEL_UNREF(constructed, "index_register");
  }

  return c;
}

void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
                                      grpc_subchannel* constructed) {
  bool done = false;
  while (!done) {
    // Compare and swap loop:
    // - take a reference to the current index
    gpr_mu_lock(&g_mu);
    grpc_avl index = grpc_avl_ref(g_subchannel_index, nullptr);
    gpr_mu_unlock(&g_mu);

    // Check to see if this key still refers to the previously
    // registered subchannel
    grpc_subchannel* c =
        static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr));
    if (c != constructed) {
      grpc_avl_unref(index, nullptr);
      break;
    }

    // compare and swap the update (some other thread may have
    // mutated the index behind us)
    grpc_avl updated =
        grpc_avl_remove(grpc_avl_ref(index, nullptr), key, nullptr);

    gpr_mu_lock(&g_mu);
    if (index.root == g_subchannel_index.root) {
      GPR_SWAP(grpc_avl, updated, g_subchannel_index);
      done = true;
    }
    gpr_mu_unlock(&g_mu);

    grpc_avl_unref(updated, nullptr);
    grpc_avl_unref(index, nullptr);
  }
}

void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {
  g_force_creation = force_creation;
}
<|endoftext|>


<commit_before>#include <tiramisu/tiramisu.h>

#include "configuration.h"

using namespace tiramisu;

int main(int argc, char **argv)
{
    tiramisu::init(); // Set default tiramisu options.

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    function matmul("matmul");

    // Declare constants
    constant p0("N", expr((int32_t) N), p_int32, true, NULL, 0, &matmul);
    constant p1("M", expr((int32_t) M), p_int32, true, NULL, 0, &matmul);
    constant p2("K", expr((int32_t) K), p_int32, true, NULL, 0, &matmul);
    constant p3("B", expr((int32_t) BLOCK), p_int32, true, NULL, 0, &matmul);

    // Declare loop iterators
    var i("i"), j("j"), k("k"), i0("i0"), i1("i1"), j0("j0"), j1("j1"), k0("k0"), k1("k1");

    // Declare cpu buffers.
    buffer b_A("b_A", {expr(M), expr(K)}, DATA_PTYPE, a_input, &matmul);
    buffer b_B("b_B", {expr(K), expr(N)}, DATA_PTYPE, a_input, &matmul);
    buffer b_C("b_C", {expr(M), expr(N)}, DATA_PTYPE, a_output, &matmul);
    // Declare gpu buffers.
    buffer b_A_gpu("b_A_gpu", {M, K}, DATA_PTYPE, a_temporary, &matmul);
    buffer b_B_gpu("b_B_gpu", {K, N}, DATA_PTYPE, a_temporary, &matmul);
    buffer b_C_gpu("b_C_gpu", {M, N}, DATA_PTYPE, a_temporary, &matmul);
    buffer b_A_gpu_tile("b_A_gpu_tile", {expr(BLOCK), expr(BLOCK)}, DATA_PTYPE, a_temporary, &matmul);
    buffer b_B_gpu_tile("b_B_gpu_tile", {expr(BLOCK), expr(BLOCK)}, DATA_PTYPE, a_temporary, &matmul);
    buffer b_acc("b_acc", {1}, DATA_PTYPE, a_temporary, &matmul);
    b_A_gpu.tag_gpu_global();
    b_B_gpu.tag_gpu_global();
    b_C_gpu.tag_gpu_global();
    b_A_gpu_tile.tag_gpu_shared();
    b_B_gpu_tile.tag_gpu_shared();
    b_acc.tag_gpu_register();

    // Declare wrappers for input buffers
    computation c_A("[M,N,K]->{c_A[i,j,k0]: 0<=i<M and 0<=j<K and 0<=k0<(K-1)/" BLOCK_STR " + 1}", expr(), false, DATA_PTYPE, &matmul);
    computation c_B("[M,N,K]->{c_B[i,j,k0]: 0<=i<K and 0<=j<N and 0<=k0<(K-1)/" BLOCK_STR " + 1}", expr(), false, DATA_PTYPE, &matmul);
    // Declare wrappers for shared arrays
    computation c_A_tile("[M,K]->{c_A_tile[i,j]: 0<=i<M and 0<=j<K}", expr(), false, DATA_PTYPE, &matmul);
    computation c_A_tile_dec("[M,N]->{c_A_tile_dec[i,j]: 0<=i<M and 0<=j<N}", allocate(b_A_gpu_tile), true, p_none, &matmul);
    computation c_A_tile_init("[M,N,K]->{c_A_tile_init[i,j,k0]: 0<=i<M and 0<=j<N and 0<=k0<(K - 1)/" BLOCK_STR " + 1}", c_A(i, j, k0), true, DATA_PTYPE, &matmul);
    computation c_B_tile("[K,N]->{c_B_tile[i,j]: 0<=i<K and 0<=j<N}", expr(), false, DATA_PTYPE, &matmul);
    computation c_B_tile_dec("[M,N]->{c_B_tile_dec[i,j]: 0<=i<M and 0<=j<N}", allocate(b_B_gpu_tile), true, p_none, &matmul);
    computation c_B_tile_init("[M,N,K]->{c_B_tile_init[i,j,k0]: 0<=i<M and 0<=j<N and 0<=k0<(K - 1)/" BLOCK_STR " + 1}", c_B(i, j, k0), true, DATA_PTYPE, &matmul);
    // Declare synchronizer computations
    computation sync1("[M,N,K]->{sync1[i,j,k0]: 0<=i<M and 0<=j<N and 0<=k0<(K-1)/" BLOCK_STR " + 1}", tiramisu::sync(), true, p_none, &matmul);
    computation sync2("[M,N,K]->{sync2[i,j,k0]: 0<=i<M and 0<=j<N and 0<=k0<(K-1)/" BLOCK_STR " + 1}", tiramisu::sync(), true, p_none, &matmul);
    // Declare wrapper computation for accumulator
    computation c_acc_dec("[M,N]->{c_acc_dec[i,j]: 0<=i<M and 0<=j<N}", allocate(b_acc), true, p_none, &matmul);
    computation c_acc_init("[M,N]->{c_acc_init[i,j]: 0<=i<M and 0<=j<N}", (DATA_TYPE) 0, true, DATA_PTYPE, &matmul);
    computation c_acc("[M,N,K]->{c_acc[i,j,k]: 0<=i<M and 0<=j<N and 0<=k<K}", expr(), true, DATA_PTYPE, &matmul);
    c_acc.set_expression(c_acc(i, j, k - 1) + c_A_tile(i, k) * c_B_tile(k, j));
    // Declare wrapper for the output buffer
    computation c_C("[M,N]->{c_C[i,j]: 0<=i<M and 0<=j<N}", expr(), true, DATA_PTYPE, &matmul);
    c_C.set_expression(c_acc(i, j, 0) * alpha + c_C(i, j) * beta);
    // Declare host-gpu transfer computations.
    computation copy_A_to_device("{copy_A_to_device[0]}", memcpy(b_A, b_A_gpu), true, p_none, &matmul);
    computation copy_B_to_device("{copy_B_to_device[0]}", memcpy(b_B, b_B_gpu), true, p_none, &matmul);
    computation copy_C_to_device("{copy_C_to_device[0]}", memcpy(b_C, b_C_gpu), true, p_none, &matmul);
    computation copy_C_to_host("{copy_C_to_host[0]}", memcpy(b_C_gpu, b_C), true, p_none, &matmul);

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Scheduling commands

    c_acc.split(k, BLOCK, k0, k1);
    c_C.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_A_tile_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_A_tile_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_B_tile_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_B_tile_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    sync1.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    sync2.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);

    copy_B_to_device.after(copy_A_to_device, computation::root);
    copy_C_to_device.after(copy_B_to_device, computation::root);
    c_A_tile_dec.after(copy_C_to_device, computation::root);
    c_B_tile_dec.after(c_A_tile_dec, j1);
    c_acc_dec.after(c_B_tile_dec, j1);
    c_acc_init.after(c_acc_dec, j1);
    c_A_tile_init.after(c_acc_init, j1);
    c_B_tile_init.after(c_A_tile_init, k0);
    sync1.after(c_B_tile_init, k0);
    c_acc.after(sync1, k0);
    sync2.after(c_acc, k0);
    c_C.after(sync2, j1);
    copy_C_to_host.after(c_C, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    c_A.set_access("{c_A[i,j,k0] -> b_A_gpu[i,k0 * " BLOCK_STR " + j % " BLOCK_STR "]}");
    c_B.set_access("{c_B[i,j,k0] -> b_B_gpu[k0 * " BLOCK_STR " + i % " BLOCK_STR ",j]}");
    c_A_tile.set_access("{c_A_tile[i, j] -> b_A_gpu_tile[i % " BLOCK_STR ", j % " BLOCK_STR "]}");
    c_A_tile_init.set_access("{c_A_tile_init[i, j, k0] -> b_A_gpu_tile[i % " BLOCK_STR ", j % " BLOCK_STR "]}");
    // Note the transpose
    c_B_tile.set_access("{c_B_tile[i, j] -> b_B_gpu_tile[j % " BLOCK_STR ", i % " BLOCK_STR "]}");
    c_B_tile_init.set_access("{c_B_tile_init[i, j, k0] -> b_B_gpu_tile[j % " BLOCK_STR ", i % " BLOCK_STR "]}");

    c_acc_init.set_access("{c_acc_init[i, j] -> b_acc[0]}");
    c_acc.set_access("{c_acc[i, j, k] -> b_acc[0]}");

    c_C.store_in(&b_C_gpu);

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Generate object files. Last argument triggers cuda compilation.
    matmul.codegen({&b_A, &b_B, &b_C}, "fct.o", true);

    // Dump the generated Halide statement (just for debugging).
    matmul.dump_halide_stmt();

    return 0;
}
<commit_msg>GPU benchmark new API<commit_after>#include <tiramisu/tiramisu.h>

#include "configuration.h"

using namespace tiramisu;

int main(int argc, char **argv)
{
    tiramisu::init("matmul");

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    // Declare loop iterators
    var i("i", 0, M), j("j", 0, N), k("k", 0, K), i0("i0"), i1("i1"), j0("j0"), j1("j1"), k0("k0", 0, (K - 1) / BLOCK + 1), k1("k1");

    // Declare cpu buffers.
    buffer b_A("b_A", {M, K}, DATA_PTYPE, a_input);
    buffer b_B("b_B", {K, N}, DATA_PTYPE, a_input);
    buffer b_C("b_C", {M, N}, DATA_PTYPE, a_output);
    // Declare gpu buffers.
    buffer b_A_gpu("b_A_gpu", {M, K}, DATA_PTYPE, a_temporary);
    buffer b_B_gpu("b_B_gpu", {K, N}, DATA_PTYPE, a_temporary);
    buffer b_C_gpu("b_C_gpu", {M, N}, DATA_PTYPE, a_temporary);
    buffer b_A_gpu_tile("b_A_gpu_tile", {BLOCK, BLOCK}, DATA_PTYPE, a_temporary);
    buffer b_B_gpu_tile("b_B_gpu_tile", {BLOCK, BLOCK}, DATA_PTYPE, a_temporary);
    buffer b_acc("b_acc", {1}, DATA_PTYPE, a_temporary);
    b_A_gpu.tag_gpu_global();
    b_B_gpu.tag_gpu_global();
    b_C_gpu.tag_gpu_global();
    b_A_gpu_tile.tag_gpu_shared();
    b_B_gpu_tile.tag_gpu_shared();
    b_acc.tag_gpu_register();

    // Declare wrappers for input buffers
    input c_A("c_A", {i, j, k0}, DATA_PTYPE);
    input c_B("c_B", {i, j, k0}, DATA_PTYPE);
    // Declare wrappers for shared arrays
    input c_A_tile("c_A_tile", {i, j}, DATA_PTYPE);
    computation c_A_tile_dec({i, j}, allocate(b_A_gpu_tile));
    computation c_A_tile_init("c_A_tile_init", {i, j, k0}, c_A(i, j, k0));
    input c_B_tile("c_B_tile", {i, j}, DATA_PTYPE);
    computation c_B_tile_dec({i, j}, allocate(b_B_gpu_tile));
    computation c_B_tile_init("c_B_tile_init", {i, j, k0}, c_B(i, j, k0));
    // Declare synchronizer computations
    computation sync1({i, j, k0}, tiramisu::sync());
    computation sync2({i, j, k0}, tiramisu::sync());
    // Declare wrapper computation for accumulator
    computation c_acc_dec({i, j}, allocate(b_acc));
    computation c_acc_init({i, j}, (DATA_TYPE) 0, DATA_PTYPE);
    computation c_acc({i, j, k}, DATA_PTYPE);
    c_acc.set_expression(c_acc(i, j, k - 1) + c_A_tile(i, k) * c_B_tile(k, j));
    // Declare wrapper for the output buffer
    computation c_C({i, j}, DATA_PTYPE);
    c_C.set_expression(c_acc(i, j, 0) * alpha + c_C(i, j) * beta);
    // Declare host-gpu transfer computations.
    computation copy_A_to_device({}, memcpy(b_A, b_A_gpu));
    computation copy_B_to_device({}, memcpy(b_B, b_B_gpu));
    computation copy_C_to_device({}, memcpy(b_C, b_C_gpu));
    computation copy_C_to_host({}, memcpy(b_C_gpu, b_C));

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Scheduling commands

    c_acc.split(k, BLOCK, k0, k1);
    c_C.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_A_tile_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_A_tile_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_B_tile_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_B_tile_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    sync1.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    sync2.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc_dec.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc_init.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);
    c_acc.gpu_tile(i, j, BLOCK, BLOCK, i0, j0, i1, j1);

    copy_B_to_device.after(copy_A_to_device, computation::root);
    copy_C_to_device.after(copy_B_to_device, computation::root);
    c_A_tile_dec.after(copy_C_to_device, computation::root);
    c_B_tile_dec.after(c_A_tile_dec, j1);
    c_acc_dec.after(c_B_tile_dec, j1);
    c_acc_init.after(c_acc_dec, j1);
    c_A_tile_init.after(c_acc_init, j1);
    c_B_tile_init.after(c_A_tile_init, k0);
    sync1.after(c_B_tile_init, k0);
    c_acc.after(sync1, k0);
    sync2.after(c_acc, k0);
    c_C.after(sync2, j1);
    copy_C_to_host.after(c_C, computation::root);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    c_A.set_access("{c_A[i,j,k0] -> b_A_gpu[i,k0 * " BLOCK_STR " + j % " BLOCK_STR "]}");
    c_B.set_access("{c_B[i,j,k0] -> b_B_gpu[k0 * " BLOCK_STR " + i % " BLOCK_STR ",j]}");
    c_A_tile.set_access("{c_A_tile[i, j] -> b_A_gpu_tile[i % " BLOCK_STR ", j % " BLOCK_STR "]}");
    c_A_tile_init.set_access("{c_A_tile_init[i, j, k0] -> b_A_gpu_tile[i % " BLOCK_STR ", j % " BLOCK_STR "]}");
    // Note the transpose
    c_B_tile.set_access("{c_B_tile[i, j] -> b_B_gpu_tile[j % " BLOCK_STR ", i % " BLOCK_STR "]}");
    c_B_tile_init.set_access("{c_B_tile_init[i, j, k0] -> b_B_gpu_tile[j % " BLOCK_STR ", i % " BLOCK_STR "]}");

    c_acc_init.store_in(&b_acc, {});
    c_acc.store_in(&b_acc, {});

    c_C.store_in(&b_C_gpu);

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Generate object files. Last argument triggers cuda compilation.
    tiramisu::codegen({&b_A, &b_B, &b_C}, "fct.o", true);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * kernel.cpp
 *
 *  Created on: Feb 20, 2017
 *      Author: garrett
 */
#include "Kernel.h"

#include "drivers/ProgrammableInterruptController.h"
#include "memory/alloc/PageFrameAllocator.h"
#include "drivers/Keyboard.h"
#include "interrupts/InterruptDescriptorTable.h"
#include "drivers/TTY/Console.h"
//#include "memory/alloc/malloc.h"
#include "memory/structures/GlobalDescriptorTable.h"
#include "memory/structures/PageTable.h"
#include "drivers/PCI/PCI.h"
#include "drivers/PCI/PCIDeviceList.h"
#include "multiboot_spec/Multiboot.h"
#include "memory/Mem.h"
#include "utils/printf/Printf.h"

InterruptDescriptorTable idt;
GlobalDescriptorTable gdt;
PageTable pageTable;
Keyboard KB;
PageFrameAllocator frameAlloc;

#if defined(__cplusplus)
extern "C" {/* Use C linkage for kernel_main. */
#endif

void kernelMain(multiboot_info_t *mbd)
{
	//turn off interrupts before configed
	asm("cli");
	//clear screen, set the pointer to the start of the VGA buffer.
	terminalInit((uint16_t *) 0xC00B8000);
	// Green on black!
	terminalSetColor(vgaEntryColor(VGA_COLOR_GREEN, VGA_COLOR_BLACK));
	terminalWriteLine("Terminal active, Welcome to ExOS!");
	terminalWriteLine("Preparing your system:");
	terminalWriteString("  Preparing GDT...");
	//build and replce grub's GDT with a custom writable one.
	gdt.build();
	gdt.load();
	terminalWriteLine(" Done!");
	terminalWriteString("  Preparing the page table...");
	//rebuild page table. replaces the one built in boot.s
	pageTable.build();
	terminalWriteLine(" Done!");
	terminalWriteString("  Setting up interrupts...");
	//sets up interrups and enables them
	interruptSetUp();
	terminalWriteLine(" Done!");
	terminalWriteString("  Preparing the memory allocator...");
	//get the memory map from grub
	getMemMap(mbd);
	//build the page frame allocator (allocate physical memory)
	frameAlloc.build();
	//set malloc's support vars
	mallocInit();
	terminalWriteLine(" Done!");
	terminalWriteString("  Finding PCI buses...");
	//find the valid PCI buses
	PCIInit();
	terminalWriteLine(" Done!");
	terminalWriteString("  Finding USB host controllers...");
	//find the (3 or less) USB host controllers. all have the same class/subclass code.
	PCIDeviceList usbHostControllers(0x0C, 0x03, false);
	terminalWriteLine(" Done!");
	terminalWriteLine("!!!!ExOS fully booted!!!!");
	printf("Test printf %d %c\n", 42, 'B');
	printf("Newline is 0x%x%c", '\n', '\n');
	uint32_t i = (uint32_t) malloc(10);
	printf("malloc returned 0x%x\n", i);
	i = (uint32_t)malloc(100);
	printf("malloc returned 0x%x\n", i);
	 i =(uint32_t) malloc(50);
	printf("malloc returned 0x%x\n", i);
	 i = (uint32_t)malloc(1);
	printf("malloc returned 0x%x\n", i);
	printf("freeing 1 byte");
	free((void*)i);
	 i = (uint32_t)malloc(1);
	printf("malloc returned 0x%x\n", i);
/*
	for (int cx = 0; cx < 10; cx++) {
		printf("%d", cx);
	}*/
	//dont return.
	while (true) {
		asm("hlt");
	}
}

#if defined(__cplusplus)
}
#endif

void interruptSetUp()
{
	//build the IDT.
	idt.build();
	//set the interrupt lines for the PIC
	PICRemap(0x20, 0x28);
	//mask the timer line
	IRQSetMask(0);
	//load it to the CPU
	idt.load();
	//enable interupts
	asm("sti");
}

<commit_msg>removed test prints<commit_after>/*
 * kernel.cpp
 *
 *  Created on: Feb 20, 2017
 *      Author: garrett
 */
#include "Kernel.h"

#include "drivers/ProgrammableInterruptController.h"
#include "memory/alloc/PageFrameAllocator.h"
#include "drivers/Keyboard.h"
#include "interrupts/InterruptDescriptorTable.h"
#include "drivers/TTY/Console.h"
//#include "memory/alloc/malloc.h"
#include "memory/structures/GlobalDescriptorTable.h"
#include "memory/structures/PageTable.h"
#include "drivers/PCI/PCI.h"
#include "drivers/PCI/PCIDeviceList.h"
#include "multiboot_spec/Multiboot.h"
#include "memory/Mem.h"
#include "utils/printf/Printf.h"

InterruptDescriptorTable idt;
GlobalDescriptorTable gdt;
PageTable pageTable;
Keyboard KB;
PageFrameAllocator frameAlloc;

#if defined(__cplusplus)
extern "C" {/* Use C linkage for kernel_main. */
#endif

void kernelMain(multiboot_info_t *mbd)
{
	//turn off interrupts before configed
	asm("cli");
	//clear screen, set the pointer to the start of the VGA buffer.
	terminalInit((uint16_t *) 0xC00B8000);
	// Green on black!
	terminalSetColor(vgaEntryColor(VGA_COLOR_GREEN, VGA_COLOR_BLACK));
	terminalWriteLine("Terminal active, Welcome to ExOS!");
	terminalWriteLine("Preparing your system:");
	terminalWriteString("  Preparing GDT...");
	//build and replce grub's GDT with a custom writable one.
	gdt.build();
	gdt.load();
	terminalWriteLine(" Done!");
	terminalWriteString("  Preparing the page table...");
	//rebuild page table. replaces the one built in boot.s
	pageTable.build();
	terminalWriteLine(" Done!");
	terminalWriteString("  Setting up interrupts...");
	//sets up interrups and enables them
	interruptSetUp();
	terminalWriteLine(" Done!");
	terminalWriteString("  Preparing the memory allocator...");
	//get the memory map from grub
	getMemMap(mbd);
	//build the page frame allocator (allocate physical memory)
	frameAlloc.build();
	//set malloc's support vars
	mallocInit();
	terminalWriteLine(" Done!");
	terminalWriteString("  Finding PCI buses...");
	//find the valid PCI buses
	PCIInit();
	terminalWriteLine(" Done!");
	terminalWriteString("  Finding USB host controllers...");
	//find the (3 or less) USB host controllers. all have the same class/subclass code.
	PCIDeviceList usbHostControllers(0x0C, 0x03, false);
	terminalWriteLine(" Done!");
	terminalWriteLine("!!!!ExOS fully booted!!!!");
	//dont return.
	while (true) {
		asm("hlt");
	}
}

#if defined(__cplusplus)
}
#endif

void interruptSetUp()
{
	//build the IDT.
	idt.build();
	//set the interrupt lines for the PIC
	PICRemap(0x20, 0x28);
	//mask the timer line
	IRQSetMask(0);
	//load it to the CPU
	idt.load();
	//enable interupts
	asm("sti");
}

<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* tests/test-fields.C
 * Written by Dan Roche
 * Copyright (C) June 2004 Dan Roche
 *
 * See COPYING for license information
 */

// to compile: g++ -I../ -I./ -I../.. -I/usr/local/algebra/include -L/usr/local/algebra/lib -lgmp -O3 -Wall -o test-fields test-fields.C ../linbox/.libs/liblinbox.a -lntl

#include "linbox/util/timer.h"
#include "linbox/field/double-fmod.h"
#include "linbox/field/ntl-zz_p.h"
#include "linbox/field/modular.h"
#include "linbox/field/modular-int.h"
#include "linbox/field/modular-double.h"
#include <iostream>
#include <iomanip>

using std::cout;
using std::endl;
using std::setw;

// Namespace in which all LinBox code resides
namespace LinBox {

template< class Element >
Element& noop( Element& a, Element& b, Element& c ) { return a; }

template< class Element >
Element& noop( Element& a, Element& b ) { return a; }

template< class Element >
Element& noop( Element& a, Element& b, Element&c, Element& d ) { return a; }

/* fieldTest is a template function to test out the performance of a given field on a
 * machine.  Taken are three arguments.  The first is a field class object.  The second
 * is an array, declared but not necessarily initialized, of seven doubles.  These
 * values will be filled with timings for add, sub, neg, mul, int, div, and axpy,
 * respectively.  The third argument is optional and specifies how many loop
 * iterations to use.
 */

template< class Field >
void fieldTest( const Field& f, double* array, int iter = 1000000 ) {

	// initialize and fill array of random elements.
	typename Field::RandIter r(f);
	typename Field::Element *elements;
	elements = new typename Field::Element[ iter * 3 ];
	for( int i = 0; i < iter*3; i++ ) {
		do { r.random( elements[i] ); }
			while( f.isZero( elements[i] ) );
	}
	typename Field::Element returnValue;

	UserTimer timer;

	// Compute overhead time for 2-argument functions.
	timer.clear();
	timer.start();
	for( int i = 0; i < iter; i++ ) {
		noop( returnValue, elements[ i*3 ] );
	}
	timer.stop();
	double overHeadTime2 = timer.time();

        // Compute overhead time for 3-argument functions.
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                noop( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        double overHeadTime3 = timer.time();

	// Compute overhead time for 4-argument functions.
	timer.clear();
	timer.start();
	for( int i = 0; i < iter; i++ ) {
		noop( returnValue, elements[ i*3 ], elements[ i*3 + 1 ], elements[ i*3 + 2 ] );
	}
	timer.stop();
	double overHeadTime4 = timer.time();

	// add
	timer.clear();
	timer.start();
	for( int i = 0; i < iter; i++ ) {
		f.add( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
	}
	timer.stop();
	array[0] = timer.time() - overHeadTime3;

        // sub
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.sub( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[1] = timer.time() - overHeadTime3;

        // neg
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.neg( returnValue, elements[ i*3 ] );
        }
        timer.stop();
        array[2] = timer.time() - overHeadTime2;

        // mul
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.mul( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[3] = timer.time() - overHeadTime3;

        // inv
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.inv( returnValue, elements[ i*3 ] );
        }
        timer.stop();
        array[4] = timer.time() - overHeadTime2;

        // div
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.div( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[5] = timer.time() - overHeadTime3;

        // axpy
        timer.clear();
        timer.start();
        for( int i = 0; i < iter; i++ ) {
                f.axpy( returnValue, elements[ i*3 ], elements[ i*3 + 1 ], elements[ i*3 + 2 ] );
        }
        timer.stop();
        array[6] = timer.time() - overHeadTime4;
}

}

using namespace LinBox;

void printTimings( double* timings ) {
	cout << setw(8) << timings[0]
	     << setw(8) << timings[1]
	     << setw(8) << timings[2]
	     << setw(8) << timings[3]
	     << setw(8) << timings[4]
	     << setw(8) << timings[5]
	     << setw(8) << timings[6];
}

int main(int argc, char** argv) {
	double timings[7];
	long prime = 268435399;
	cout << setw(20) << "Field Name"
	     << setw(8) << "add"
	     << setw(8) << "sub"
	     << setw(8) << "neg"
	     << setw(8) << "mul"
	     << setw(8) << "inv"
	     << setw(8) << "div"
	     << setw(8) << "axpy" << endl;

	DoubleFmod field1( prime );
	fieldTest( field1, timings );
	cout << setw(20) << "DoubleFmod";
	printTimings( timings );
	cout << endl;

	Modular<double> field15( prime );
	fieldTest( field15, timings );
	cout << setw(20) << "Modular<double>";
	printTimings( timings );
	cout << endl;

	NTL_zz_p field2( prime );
	fieldTest( field2, timings );
	cout << setw(20) << "NTL_zz_p";
	printTimings( timings );
	cout << endl;

	Modular<int> field3( prime );
	fieldTest( field3, timings );
	cout << setw(20) << "Modular<int>";
	printTimings( timings );
	cout << endl;

	return 0;
}
<commit_msg>Dan Roche, June 2004 Converting timing reports to mops, million operations per second, added dot product timings.<commit_after>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* tests/test-fields.C
 * Written by Dan Roche
 * Copyright (C) June 2004 Dan Roche
 *
 * See COPYING for license information
 */

#include "linbox/util/timer.h"
#include "linbox/field/givaro-gfq.h"
#include "linbox/field/ntl-zz_p.h"
#include "linbox/field/modular.h"
#include "linbox/field/modular-int.h"
#include "linbox/field/modular-double.h"
#include "linbox/vector/stream.h"
#include <iostream>
#include <iomanip>

using std::cout;
using std::endl;
using std::setw;

// Namespace in which all LinBox code resides
namespace LinBox {

template< class Element >
Element& noop( Element& a, const Element& b ) { return a = b; }

/* fieldTest is a template function to test out the performance of a given field on a
 * machine.  Taken are three arguments.  The first is a field class object.  The second
 * is an array, declared but not necessarily initialized, of ten doubles.  The
 * first nine values will be filled with mops for add, sub, neg, mul, int, div,
 * axpy, dot1, and dot2, respectively.  (Dot1 is dense*dense, Dot2 is dense*sparse).
 * The last value is filled with mops for walking through an array of size iter.
 * The third argument is optional and specifies how many loop iterations to use.
 */

template< class Field >
void fieldTest( const Field& f, double* array, long iter = 1000000 ) {

	long vectorSize = 10000;
	float sparsity = .01;
	int i;

	// initialize and fill array of random elements.
	typename Field::RandIter r(f);
	typename Field::Element *elements;
	elements = new typename Field::Element[ iter * 3 ];
	for( int i = 0; i < iter*3; i++ ) {
		do { r.random( elements[i] ); }
			while( f.isZero( elements[i] ) );
	}
	register typename Field::Element returnValue;

	// initialize random vector streams
	RandomDenseStream<Field> dense1( f, vectorSize, iter/vectorSize );
	RandomDenseStream<Field> dense2( f, vectorSize, iter/vectorSize );
	RandomSparseStream<Field> sparse( f, sparsity, vectorSize, 0 );

	// initialize individual vectors to hold results
	typename RandomDenseStream<Field>::Vector dv1;
	typename RandomDenseStream<Field>::Vector dv2;
	typename RandomSparseStream<Field>::Vector sv;
	VectorWrapper::ensureDim (dv1,vectorSize);
	VectorWrapper::ensureDim (dv2,vectorSize);
	VectorWrapper::ensureDim (sv,vectorSize);

	VectorDomain<Field> VD( f );

	UserTimer timer;

	// Compute overhead time for non-vector functions.
	timer.clear();
	timer.start();
	for( i = 0; i < iter; i++ ) {
		noop( returnValue, elements[ i*3 ] );

	}
	timer.stop();
	double overHeadTime = timer.time();

	// Compute overhead time for DotProduct1( dense*dense )
	timer.clear();
	timer.start();
	while( dense1 && dense2 ) {
		dense1.get( dv1 );
		dense2.get( dv2 );
	}
	timer.stop();
	dense1.reset();
	dense2.reset();
	double overHeadTimeDD = timer.time();

	// Compute overhead time for DotProduct2( dense*sparse )
	timer.clear();
	timer.start();
        while( dense1 ) {
                dense1.get( dv1 );
                for( float fi = 0; fi < 1; fi += sparsity ) sparse.get( sv );
        }
	timer.stop();
	dense1.reset();
	sparse.reset();
	double overHeadTimeDS = timer.time();

	// add
	timer.clear();
	timer.start();
	for( i = 0; i < iter; i++ ) {
		f.add( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
	}
	timer.stop();
	array[0] = timer.time() - overHeadTime;

        // sub
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.sub( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[1] = timer.time() - overHeadTime;

        // neg
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.neg( returnValue, elements[ i*3 ] );
        }
        timer.stop();
        array[2] = timer.time() - overHeadTime;

        // mul
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.mul( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[3] = timer.time() - overHeadTime;

        // inv
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.inv( returnValue, elements[ i*3 ] );
        }
        timer.stop();
        array[4] = timer.time() - overHeadTime;

        // div
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.div( returnValue, elements[ i*3 ], elements[ i*3 + 1 ] );
        }
        timer.stop();
        array[5] = timer.time() - overHeadTime;

        // axpy
        timer.clear();
        timer.start();
        for( i = 0; i < iter; i++ ) {
                f.axpy( returnValue, elements[ i*3 ], elements[ i*3 + 1 ],
			elements[ i*3 + 2 ] );
        }
        timer.stop();
        array[6] = timer.time() - overHeadTime;

	// DotProduct1 ( dense * dense )
	timer.clear();
	timer.start();
        while( dense1 && dense2 ) {
                dense1.get( dv1 );
                dense2.get( dv2 );
		VD.dot( returnValue, dv1, dv2 );
        }
	timer.stop();
	dense1.reset();
	dense2.reset();
	array[7] = timer.time() - overHeadTimeDD;

	// DotProduct2 ( dense * sparse )
	timer.clear();
	timer.start();
        while( dense1 && sparse ) {
                dense1.get( dv1 );
                for (float fi = 0; fi < 1; fi += sparsity) {
			sparse.get( sv );
			VD.dot( returnValue, dv1, sv );
		}
	}
	timer.stop();
	dense1.reset();
	sparse.reset();
	array[8] = timer.time() - overHeadTimeDS;

	// Convert timings to mops (million operations per second)
	array[9] = overHeadTime;
	for( i = 0; i < 10; i++ )
		array[i] = iter / (array[i] * 1000000);
}

}

using namespace LinBox;

void printTimings( double* timings ) {
	cout << setw(8) << timings[0] << ' '
	     << setw(8) << timings[1] << ' '
	     << setw(8) << timings[2] << ' '
	     << setw(8) << timings[3] << ' '
	     << setw(8) << timings[4] << ' '
	     << setw(8) << timings[5] << ' '
	     << setw(8) << timings[6] << ' '
	     << setw(8) << timings[7] << ' '
	     << setw(8) << timings[8] << ' '
	     << setw(8) << timings[9];
}

int main(int argc, char** argv) {
	double timings[10];
	long prime = 65521;
	cout << setw(15) << "Field Name"
	     << setw(8) << "add"
	     << setw(9) << "sub"
	     << setw(9) << "neg"
	     << setw(9) << "mul"
	     << setw(9) << "inv"
	     << setw(9) << "div"
	     << setw(9) << "axpy"
	     << setw(9) << "dot d*d"
	     << setw(9) << "dot d*s"
	     << setw(9) << "array" << endl;

	Modular<double> field1( prime );
	fieldTest( field1, timings );
	cout << setw(15) << "Modular<double>";
	printTimings( timings );
	cout << endl;

	NTL_zz_p field2( prime );
	fieldTest( field2, timings );
	cout << setw(15) << "NTL_zz_p";
	printTimings( timings );
	cout << endl;

	Modular<int> field3( prime );
	fieldTest( field3, timings );
	cout << setw(15) << "Modular<int>";
	printTimings( timings );
	cout << endl;

	return 0;
}
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return style == SCE_C_COMMENT ||
		style == SCE_C_COMMENTDOC ||
		style == SCE_C_COMMENTDOCKEYWORD ||
		style == SCE_C_COMMENTDOCKEYWORDERROR;
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelCurrent++;
			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (foldComment && (style == SCE_C_COMMENTLINE)) {
			if ((ch == '/') && (chNext == '/')) {
				char chNext2 = styler.SafeGetCharAt(i + 2);
				if (chNext2 == '{') {
					levelCurrent++;
				} else if (chNext2 == '}') {
					levelCurrent--;
				}
			}
		}
		if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
			if (ch == '#') {
				unsigned int j=i+1;
				while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
					j++;
				}
				if (styler.Match(j, "region") || styler.Match(j, "if")) {
					levelCurrent++;
				} else if (styler.Match(j, "end")) {
					levelCurrent--;
				}
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<commit_msg>Jump out of preprocessor mode when a comment, // or /*, is found.<commit_after>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if ((sc.atLineEnd) || (sc.Match('/', '*')) || (sc.Match('/', '/'))) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return style == SCE_C_COMMENT ||
		style == SCE_C_COMMENTDOC ||
		style == SCE_C_COMMENTDOCKEYWORD ||
		style == SCE_C_COMMENTDOCKEYWORDERROR;
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelCurrent++;
			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (foldComment && (style == SCE_C_COMMENTLINE)) {
			if ((ch == '/') && (chNext == '/')) {
				char chNext2 = styler.SafeGetCharAt(i + 2);
				if (chNext2 == '{') {
					levelCurrent++;
				} else if (chNext2 == '}') {
					levelCurrent--;
				}
			}
		}
		if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
			if (ch == '#') {
				unsigned int j=i+1;
				while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
					j++;
				}
				if (styler.Match(j, "region") || styler.Match(j, "if")) {
					levelCurrent++;
				} else if (styler.Match(j, "end")) {
					levelCurrent--;
				}
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<|endoftext|>