<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"

MugenReader::MugenReader( const char * file ){
  ifile.open( file );
  myfile = string( file );
}

MugenReader::MugenReader( const string & file ){
  ifile.open( file.c_str() );
  myfile = file;
}

MugenReader::~MugenReader(){

  for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
      delete (*i);
  }

}

const std::vector< MugenSection * > & MugenReader::getCollection() throw(MugenException){

  if ( !ifile ){
      throw MugenException( std::string("Could not open ") + myfile );
  }

  std::string line;

  const char openbracket = '[';
  const char closebracket = ']';
  const char comment = ';';
  const char seperator = ',';
  const char colon = ':';
  const char equal = '=';
  const char quote = '"';

  SearchState state = Section;
  // Our section and items
  MugenSection * sectionHolder = 0;
  // Marker for areas
  bool beginSection = false;
  bool inQuote = false;

  while( !ifile.eof() ){
      getline( ifile, line );
      // Use to hold section or content in the options
      std::string contentHolder = "";
      // Place holder to put back all the grabbed content
      MugenItemContent *itemHolder = new MugenItemContent();
      // Needed to kill loop
      bool breakLoop = false;

      for( unsigned int i = 0; i < line.size(); ++i ){
	    // Go to work
	    switch( state ){
	      case Section:{
		// Done with this
		if( line[i] == comment ){
		  breakLoop = true;
		  break;
		}
		else if ( line[i] == ' ' && !beginSection )continue;
		//Start grabbing our section
		else if( line[i] == openbracket){
		  beginSection = true;
		}
		//End of our section store and go to ContentGet
		else if( line[i] == closebracket){
		  sectionHolder = new MugenSection();
		  sectionHolder->setHeader( contentHolder );
		  state = ContentGet;
		  beginSection = false;
		  breakLoop = true;
		  break;
		}
		else if( beginSection )contentHolder += line[i];
	      }
	      break;
	      case ContentGet:
	      default:{
		// Done with this
		if( line[i] == comment ){
		  if( itemHolder->hasItems() ){
		    if( !contentHolder.empty() ){
		      *itemHolder << contentHolder;
		    }
		    *sectionHolder << itemHolder;
		  }
		  breakLoop = true;
		  break;
		}
		// Check if we are near the end to kill it
		if( i+1 == line.size() && !contentHolder.empty() ){
		    if ( line[i] != ' ' ) contentHolder += line[i];
		    *itemHolder << contentHolder;
		    *sectionHolder << itemHolder;
		    breakLoop = true;
		    break;
		}
		// Buh bye spaces
		if ( line[i] == ' ' && !inQuote ){
		  continue;
		}
		// This section is done, push it on the stack and reset everything
		if( line[i] == openbracket ){
		  if( sectionHolder->hasItems() )addSection( sectionHolder );
		  beginSection = true;
		  state = Section;
		  contentHolder = "";
		  break;
		}
		// We got one push back the other and reset the holder to get the next
		else if( line[i] == colon || line[i] == seperator || line[i] == equal ){
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// We has a quote begin or end it
		else if( line[i] == quote ){
		  inQuote = !inQuote;
		}
		//Start grabbing our item
		else contentHolder += line[i];
	      }
	      break;
	    }
	    if( breakLoop )break;
      }
  }
  // Add in last section
  if( sectionHolder->hasItems() )addSection( sectionHolder );

  return collection;
}

void MugenReader::addSection( MugenSection * section ){
  collection.push_back ( section );
}

<commit_msg>Improved mugen config file parser<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"

// Check for Clsn
bool checkClsn( const std::string &clsn ){
  return ( clsn.find("Clsn") != std::string::npos );
}

MugenReader::MugenReader( const char * file ){
  ifile.open( file );
  myfile = string( file );
}

MugenReader::MugenReader( const string & file ){
  ifile.open( file.c_str() );
  myfile = file;
}

MugenReader::~MugenReader(){

  for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
      delete (*i);
  }

}

const std::vector< MugenSection * > & MugenReader::getCollection() throw(MugenException){

  if ( !ifile ){
      throw MugenException( std::string("Could not open ") + myfile );
  }

  std::string line;

  const char openbracket = '[';
  const char closebracket = ']';
  const char openparen = '(';
  const char closeparen = ')';
  const char comment = ';';
  const char seperator = ',';
  const char colon = ':';
  const char equal = '=';
  const char notequal = '!';
  const char quote = '"';
  const char orcondition = '|';
  const char andcondition = '&';
  const char greater = '>';
  const char less = '<';
  const char add = '+';
  const char multiply = '*';

  SearchState state = Section;
  // Our section and items
  MugenSection * sectionHolder = 0;
  // Marker for areas
  bool beginSection = false;
  bool inQuote = false;

  while( !ifile.eof() ){
      getline( ifile, line );
      // Use to hold section or content in the options
      std::string contentHolder = "";
      // Place holder to put back all the grabbed content
      MugenItemContent *itemHolder = new MugenItemContent();
      // Needed to kill loop
      bool breakLoop = false;

      for( unsigned int i = 0; i < line.size(); ++i ){
	    // Go to work
	    switch( state ){
	      case Section:{
		// Done with this
		if( line[i] == comment ){
		  breakLoop = true;
		  break;
		}
		else if ( line[i] == ' ' && !beginSection )continue;
		//Start grabbing our section
		else if( line[i] == openbracket){
		  beginSection = true;
		}
		//End of our section store and go to ContentGet
		else if( line[i] == closebracket){
		  sectionHolder = new MugenSection();
		  sectionHolder->setHeader( contentHolder );
		  state = ContentGet;
		  beginSection = false;
		  breakLoop = true;
		  break;
		}
		else if( beginSection )contentHolder += line[i];
	      }
	      break;
	      case ContentGet:
	      default:{
		// Done with this
		if( line[i] == comment ){
		  if( itemHolder->hasItems() ){
		    if( !contentHolder.empty() ){
		      *itemHolder << contentHolder;
		    }
		    *sectionHolder << itemHolder;
		  }
		  breakLoop = true;
		  break;
		}
		// Check if we are near the end to kill it
		if( i+1 == line.size() && !contentHolder.empty() ){
		    if ( line[i] != ' ' ) contentHolder += line[i];
		    *itemHolder << contentHolder;
		    *sectionHolder << itemHolder;
		    breakLoop = true;
		    break;
		}
		// Buh bye spaces
		if ( line[i] == ' ' && !inQuote ){
		  continue;
		}
		// Check if this section is done, push it on the stack and reset everything
		if( line[i] == openbracket && !checkClsn( contentHolder ) && !itemHolder->hasItems() ){
		  if( sectionHolder->hasItems() )addSection( sectionHolder );
		  beginSection = true;
		  state = Section;
		  contentHolder = "";
		  break;
		}
		// It's peanut butter bracket time
		else if( line[i] == openbracket && !checkClsn( contentHolder ) && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = openbracket;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		else if( line[i] == closebracket && !checkClsn( contentHolder )  && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = closebracket;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// We got one push back the other and reset the holder to get the next
		else if( line[i] == colon || line[i] == seperator ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Conditional or
		else if( line[i] == orcondition && !inQuote ){
		  // Check to see if the next line is another |
		  if( i+1 != line.size() ){
		    if( line[i+1] == orcondition ){
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = orcondition;
		    }
		    else {
		      contentHolder += orcondition;
		      *itemHolder << contentHolder;
		      contentHolder = "";
		    }
		  }
		}
		// Conditional and
		else if( line[i] == andcondition && !inQuote ){
		  // Check to see if the next line is another &
		  if( i+1 != line.size() ){
		    if( line[i+1] == andcondition ){
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = andcondition;
		    }
		    else {
		      contentHolder += andcondition;
		      *itemHolder << contentHolder;
		      contentHolder = "";
		    }
		  }
		}
		// Parenthesis open
		else if(line[i] == openparen && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = openparen;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Parenthesis closed
		else if(line[i] == closeparen && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = closeparen;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Equal
		else if(line[i] == equal && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = equal;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Not Equal
		else if( line[i] == notequal && !inQuote ){
		  // Check to see if the next line is =
		  if( i+1 != line.size() ){
		    if( line[i+1] == equal ){
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = "!=";
			*itemHolder << contentHolder;
			contentHolder = "";
			i++;
		    }
		  }
		}
		// Greater than
		else if(line[i] == greater && !inQuote ){
		   // Check to see if the next line is =
		  if( i+1 != line.size() ){
		    if( line[i+1] == equal ){
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = ">=";
			*itemHolder << contentHolder;
			contentHolder = "";
			i++;
		    } else{
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = greater;
			*itemHolder << contentHolder;
			contentHolder = "";
		    }
		  }
		}
		// Less than
		else if(line[i] == less && !inQuote ){
		   // Check to see if the next line is =
		  if( i+1 != line.size() ){
		    if( line[i+1] == equal ){
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = "<=";
			*itemHolder << contentHolder;
			contentHolder = "";
			i++;
		    } else{
			if( !contentHolder.empty() ) *itemHolder << contentHolder;
			contentHolder = less;
			*itemHolder << contentHolder;
			contentHolder = "";
		    }
		  }
		}
		// Add
		else if(line[i] == add && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = add;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// Multiply
		else if(line[i] == multiply && !inQuote ){
		  if( !contentHolder.empty() ) *itemHolder << contentHolder;
		  contentHolder = multiply;
		  *itemHolder << contentHolder;
		  contentHolder = "";
		}
		// We has a quote begin or end it
		else if( line[i] == quote ){
		  inQuote = !inQuote;
		}
		//Start grabbing our item
		else contentHolder += line[i];
	      }
	      break;
	    }
	    if( breakLoop )break;
      }
  }
  // Add in last section
  if( sectionHolder->hasItems() )addSection( sectionHolder );

  return collection;
}

void MugenReader::addSection( MugenSection * section ){
  collection.push_back ( section );
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "codegenerator.h"

#include "codegensettings.h"

#include <coreplugin/icore.h>

#include <utils/codegeneration.h>

#include <QDomDocument>
#include <QSettings>
#include <QTextStream>
#include <QXmlStreamReader>

namespace QtSupport {

// Change the contents of a DOM element to a new value if it matches
// a predicate
template <class Predicate>
bool changeDomElementContents(const QDomElement &element,
                              Predicate p,
                              const QString &newValue,
                              QString *ptrToOldValue = 0)
{
    // Find text in "<element>text</element>"
    const QDomNodeList children = element.childNodes();
    if (children.size() != 1)
        return false;
    const QDomNode first = children.at(0);
    if (first.nodeType() != QDomNode::TextNode)
        return false;
    QDomCharacterData data = first.toCharacterData();
    const QString oldValue = data.data();

    if (p(oldValue)) {
        if (ptrToOldValue)
            *ptrToOldValue = oldValue;
        data.setData(newValue);
        return true;
    }
    return false;
}

namespace {
bool truePredicate(const QString &) { return true; }

// Predicate that matches a string value
class MatchPredicate {
public:
    MatchPredicate(const QString &m) : m_match(m) {}
    bool operator()(const QString &s) const { return s == m_match; }
private:
    const QString m_match;
};

// Change <sender> and <receiver> in a Dom UI <connections> list
// if they match the class name passed on
void changeDomConnectionList(const QDomElement &connectionsNode,
                             const QString &oldClassName,
                             const QString &newClassName)
{
    const MatchPredicate oldClassPredicate(oldClassName);
    const QString senderTag = QLatin1String("sender");
    const QString receiverTag = QLatin1String("receiver");
    const QDomNodeList connections = connectionsNode.childNodes();
    const int connectionsCount =  connections.size();
    // Loop <connection>
    for (int c = 0; c < connectionsCount; c++) {
        const QDomNodeList connectionElements = connections.at(c).childNodes();
        const int connectionElementCount = connectionElements.count();
        // Loop <sender>, <receiver>, <signal>, <slot>
        for (int ce = 0; ce < connectionElementCount; ce++) {
            const QDomNode connectionElementNode = connectionElements.at(ce);
            if (connectionElementNode.isElement()) {
                const QDomElement connectionElement = connectionElementNode.toElement();
                const QString tagName =  connectionElement.tagName();
                if (tagName == senderTag || tagName == receiverTag)
                    changeDomElementContents(connectionElement, oldClassPredicate, newClassName);
            }
        }
    }
}
}

// Change the UI class name in UI xml: This occurs several times, as contents
// of the <class> element, as name of the first <widget> element, and possibly
// in the signal/slot connections

QString CodeGenerator::changeUiClassName(const QString &uiXml, const QString &newUiClassName)
{
    QDomDocument domUi;
    if (!domUi.setContent(uiXml)) {
        qWarning("Failed to parse:\n%s", uiXml.toUtf8().constData());
        return uiXml;
    }

    bool firstWidgetElementFound = false;
    QString oldClassName;

    // Loop first level children. First child is <ui>
    const QDomNodeList children = domUi.firstChildElement().childNodes();
    const QString classTag = QLatin1String("class");
    const QString widgetTag = QLatin1String("widget");
    const QString connectionsTag = QLatin1String("connections");
    const int count = children.size();
    for (int i = 0; i < count; i++) {
        const QDomNode node = children.at(i);
        if (node.isElement()) {
            // Replace <class> element text
            QDomElement element = node.toElement();
            const QString name = element.tagName();
            if (name == classTag) {
                if (!changeDomElementContents(element, truePredicate, newUiClassName, &oldClassName)) {
                    qWarning("Unable to change the <class> element:\n%s", uiXml.toUtf8().constData());
                    return uiXml;
                }
            } else {
                // Replace first <widget> element name attribute
                if (!firstWidgetElementFound && name == widgetTag) {
                    firstWidgetElementFound = true;
                    const QString nameAttribute = QLatin1String("name");
                    if (element.hasAttribute(nameAttribute))
                        element.setAttribute(nameAttribute, newUiClassName);
                } else {
                    // Replace <sender>, <receiver> tags of dialogs.
                    if (name == connectionsTag)
                        changeDomConnectionList(element, oldClassName, newUiClassName);
                }
            }
        }
    }
    const QString rc = domUi.toString();
    return rc;
}

bool CodeGenerator::uiData(const QString &uiXml, QString *formBaseClass, QString *uiClassName)
{
    // Parse UI xml to determine
    // 1) The ui class name from "<class>Designer::Internal::FormClassWizardPage</class>"
    // 2) the base class from: widget class="QWizardPage"...
    QXmlStreamReader reader(uiXml);
    while (!reader.atEnd()) {
        if (reader.readNext() == QXmlStreamReader::StartElement) {
            if (reader.name() == QLatin1String("class")) {
                *uiClassName = reader.readElementText();
            } else {
                if (reader.name() == QLatin1String("widget")) {
                    const QXmlStreamAttributes attrs = reader.attributes();
                    *formBaseClass = attrs.value(QLatin1String("class")).toString();
                    return !uiClassName->isEmpty() && !formBaseClass->isEmpty();
                }
            }
        }
    }
    return false;
}

QString CodeGenerator::qtIncludes(const QStringList &qt4, const QStringList &qt5)
{
    CodeGenSettings settings;
    settings.fromSettings(Core::ICore::settings());

    QString result;
    QTextStream str(&result);
    Utils::writeQtIncludeSection(qt4, qt5, settings.addQtVersionCheck, settings.includeQtModule, str);
    return result;
}

} // namespace QtSupport
<commit_msg>QtSupport: Code cosmetics<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "codegenerator.h"

#include "codegensettings.h"

#include <coreplugin/icore.h>

#include <utils/codegeneration.h>

#include <QDomDocument>
#include <QSettings>
#include <QTextStream>
#include <QXmlStreamReader>

namespace QtSupport {

// Change the contents of a DOM element to a new value if it matches
// a predicate
template <class Predicate>
bool changeDomElementContents(const QDomElement &element,
                              Predicate p,
                              const QString &newValue,
                              QString *ptrToOldValue = 0)
{
    // Find text in "<element>text</element>"
    const QDomNodeList children = element.childNodes();
    if (children.size() != 1)
        return false;
    const QDomNode first = children.at(0);
    if (first.nodeType() != QDomNode::TextNode)
        return false;
    QDomCharacterData data = first.toCharacterData();
    const QString oldValue = data.data();

    if (p(oldValue)) {
        if (ptrToOldValue)
            *ptrToOldValue = oldValue;
        data.setData(newValue);
        return true;
    }
    return false;
}

namespace {
bool truePredicate(const QString &) { return true; }

// Predicate that matches a string value
class MatchPredicate {
public:
    MatchPredicate(const QString &m) : m_match(m) {}
    bool operator()(const QString &s) const { return s == m_match; }
private:
    const QString m_match;
};

// Change <sender> and <receiver> in a Dom UI <connections> list
// if they match the class name passed on
void changeDomConnectionList(const QDomElement &connectionsNode,
                             const QString &oldClassName,
                             const QString &newClassName)
{
    const MatchPredicate oldClassPredicate(oldClassName);
    const QString senderTag = QLatin1String("sender");
    const QString receiverTag = QLatin1String("receiver");
    const QDomNodeList connections = connectionsNode.childNodes();
    const int connectionsCount =  connections.size();
    // Loop <connection>
    for (int c = 0; c < connectionsCount; c++) {
        const QDomNodeList connectionElements = connections.at(c).childNodes();
        const int connectionElementCount = connectionElements.count();
        // Loop <sender>, <receiver>, <signal>, <slot>
        for (int ce = 0; ce < connectionElementCount; ce++) {
            const QDomNode connectionElementNode = connectionElements.at(ce);
            if (connectionElementNode.isElement()) {
                const QDomElement connectionElement = connectionElementNode.toElement();
                const QString tagName =  connectionElement.tagName();
                if (tagName == senderTag || tagName == receiverTag)
                    changeDomElementContents(connectionElement, oldClassPredicate, newClassName);
            }
        }
    }
}
}

// Change the UI class name in UI xml: This occurs several times, as contents
// of the <class> element, as name of the first <widget> element, and possibly
// in the signal/slot connections

QString CodeGenerator::changeUiClassName(const QString &uiXml, const QString &newUiClassName)
{
    QDomDocument domUi;
    if (!domUi.setContent(uiXml)) {
        qWarning("Failed to parse:\n%s", uiXml.toUtf8().constData());
        return uiXml;
    }

    bool firstWidgetElementFound = false;
    QString oldClassName;

    // Loop first level children. First child is <ui>
    const QDomNodeList children = domUi.firstChildElement().childNodes();
    const QString classTag = QLatin1String("class");
    const QString widgetTag = QLatin1String("widget");
    const QString connectionsTag = QLatin1String("connections");
    const int count = children.size();
    for (int i = 0; i < count; i++) {
        const QDomNode node = children.at(i);
        if (node.isElement()) {
            // Replace <class> element text
            QDomElement element = node.toElement();
            const QString name = element.tagName();
            if (name == classTag) {
                if (!changeDomElementContents(element, truePredicate, newUiClassName, &oldClassName)) {
                    qWarning("Unable to change the <class> element:\n%s", uiXml.toUtf8().constData());
                    return uiXml;
                }
            } else {
                // Replace first <widget> element name attribute
                if (!firstWidgetElementFound && name == widgetTag) {
                    firstWidgetElementFound = true;
                    const QString nameAttribute = QLatin1String("name");
                    if (element.hasAttribute(nameAttribute))
                        element.setAttribute(nameAttribute, newUiClassName);
                } else {
                    // Replace <sender>, <receiver> tags of dialogs.
                    if (name == connectionsTag)
                        changeDomConnectionList(element, oldClassName, newUiClassName);
                }
            }
        }
    }
    const QString rc = domUi.toString();
    return rc;
}

bool CodeGenerator::uiData(const QString &uiXml, QString *formBaseClass, QString *uiClassName)
{
    // Parse UI xml to determine
    // 1) The ui class name from "<class>Designer::Internal::FormClassWizardPage</class>"
    // 2) the base class from: widget class="QWizardPage"...
    QXmlStreamReader reader(uiXml);
    while (!reader.atEnd()) {
        if (reader.readNext() == QXmlStreamReader::StartElement) {
            if (reader.name() == QLatin1String("class")) {
                *uiClassName = reader.readElementText();
            } else if (reader.name() == QLatin1String("widget")) {
                const QXmlStreamAttributes attrs = reader.attributes();
                *formBaseClass = attrs.value(QLatin1String("class")).toString();
                return !uiClassName->isEmpty() && !formBaseClass->isEmpty();
            }
        }
    }
    return false;
}

QString CodeGenerator::qtIncludes(const QStringList &qt4, const QStringList &qt5)
{
    CodeGenSettings settings;
    settings.fromSettings(Core::ICore::settings());

    QString result;
    QTextStream str(&result);
    Utils::writeQtIncludeSection(qt4, qt5, settings.addQtVersionCheck, settings.includeQtModule, str);
    return result;
}

} // namespace QtSupport
<|endoftext|>


<commit_before>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

// A program with a main that is suitable for unittests, including those
// that also define microbenchmarks.  Based on whether the user specified
// the --benchmark_filter flag which specifies which benchmarks to run,
// we will either run benchmarks or run the gtest tests in the program.

#include "tensorflow/core/platform/platform.h"
#include "tensorflow/core/platform/types.h"

#if defined(PLATFORM_GOOGLE) || defined(__ANDROID__)
// main() is supplied by gunit_main
#else
#include "gtest/gtest.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/platform/test_benchmark.h"

GTEST_API_ int main(int argc, char** argv) {
  std::cout << "Running main() from test_main.cc\n";

  testing::InitGoogleTest(&argc, argv);
  for (int i = 1; i < argc; i++) {
    if (tensorflow::StringPiece(argv[i]).starts_with("--benchmarks=")) {
      const char* pattern = argv[i] + strlen("--benchmarks=");
      tensorflow::testing::Benchmark::Run(pattern);
      return 0;
    }
  }
  return RUN_ALL_TESTS();
}
#endif
<commit_msg>Internal change.<commit_after>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

// A program with a main that is suitable for unittests, including those
// that also define microbenchmarks.  Based on whether the user specified
// the --benchmark_filter flag which specifies which benchmarks to run,
// we will either run benchmarks or run the gtest tests in the program.

#include "tensorflow/core/platform/platform.h"
#include "tensorflow/core/platform/types.h"

#if defined(PLATFORM_GOOGLE) || defined(__ANDROID__)
// main() is supplied by gunit_main
#else
#include "gtest/gtest.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/test_benchmark.h"

GTEST_API_ int main(int argc, char** argv) {
  std::cout << "Running main() from test_main.cc\n";

  testing::InitGoogleTest(&argc, argv);
  for (int i = 1; i < argc; i++) {
    if (tensorflow::str_util::StartsWith(argv[i], "--benchmarks=")) {
      const char* pattern = argv[i] + strlen("--benchmarks=");
      tensorflow::testing::Benchmark::Run(pattern);
      return 0;
    }
  }
  return RUN_ALL_TESTS();
}
#endif
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -debug-info-kind=line-tables-only %s -o - | FileCheck %s
// Crasher for PR22929.
class Base {
  virtual void VariadicFunction(...);
};

class Derived : public virtual Base {
  virtual void VariadicFunction(...);
};

void Derived::VariadicFunction(...) { }

// CHECK: define void @_ZN7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP:[0-9]+]]
// CHECK: ret void, !dbg ![[LOC:[0-9]+]]
// CHECK-LABEL: define void @_ZT{{.+}}N7Derived16VariadicFunctionEz(
// CHECK: ret void, !dbg ![[LOC:[0-9]+]]
//
// CHECK: ![[SP]] = distinct !DISubprogram(name: "VariadicFunction"
// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]])
<commit_msg>Update testcase for upstream LLVM changes (r302469).<commit_after>// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -debug-info-kind=line-tables-only %s -o - | FileCheck %s
// Crasher for PR22929.
class Base {
  virtual void VariadicFunction(...);
};

class Derived : public virtual Base {
  virtual void VariadicFunction(...);
};

void Derived::VariadicFunction(...) { }

// CHECK: define void @_ZN7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP:[0-9]+]]
// CHECK: ret void, !dbg ![[LOC:[0-9]+]]
// CHECK: define void @_ZT{{.+}}N7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP_I:[0-9]+]]
// CHECK: ret void, !dbg ![[LOC_I:[0-9]+]]
//
// CHECK: ![[SP]] = distinct !DISubprogram(name: "VariadicFunction"
// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]])
// CHECK: ![[SP_I]] = distinct !DISubprogram(name: "VariadicFunction"
// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]])
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 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 "test/core/end2end/end2end_tests.h"

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

#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/surface/channel_init.h"
#include "test/core/end2end/cq_verifier.h"

static bool g_enable_filter = false;

static void* tag(intptr_t t) { return (void*)t; }

static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
                                            const char* test_name,
                                            grpc_channel_args* client_args,
                                            grpc_channel_args* server_args) {
  grpc_end2end_test_fixture f;
  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
  f = config.create_fixture(client_args, server_args);
  config.init_server(&f, server_args);
  config.init_client(&f, client_args);
  return f;
}

static gpr_timespec n_seconds_from_now(int n) {
  return grpc_timeout_seconds_to_deadline(n);
}

static gpr_timespec five_seconds_from_now(void) {
  return n_seconds_from_now(5);
}

static void drain_cq(grpc_completion_queue* cq) {
  grpc_event ev;
  do {
    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
}

static void shutdown_server(grpc_end2end_test_fixture* f) {
  if (!f->server) return;
  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
                                         grpc_timeout_seconds_to_deadline(5),
                                         nullptr)
                 .type == GRPC_OP_COMPLETE);
  grpc_server_destroy(f->server);
  f->server = nullptr;
}

static void shutdown_client(grpc_end2end_test_fixture* f) {
  if (!f->client) return;
  grpc_channel_destroy(f->client);
  f->client = nullptr;
}

static void end_test(grpc_end2end_test_fixture* f) {
  shutdown_server(f);
  shutdown_client(f);

  grpc_completion_queue_shutdown(f->cq);
  drain_cq(f->cq);
  grpc_completion_queue_destroy(f->cq);
  grpc_completion_queue_destroy(f->shutdown_cq);
}

/* Simple request via a server filter that always closes the stream.*/
static void test_request(grpc_end2end_test_config config) {
  grpc_call* c;
  grpc_call* s;
  grpc_slice request_payload_slice =
      grpc_slice_from_copied_string("hello world");
  grpc_byte_buffer* request_payload =
      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
  grpc_end2end_test_fixture f =
      begin_test(config, "filter_causes_close", nullptr, nullptr);
  cq_verifier* cqv = cq_verifier_create(f.cq);
  grpc_op ops[6];
  grpc_op* op;
  grpc_metadata_array initial_metadata_recv;
  grpc_metadata_array trailing_metadata_recv;
  grpc_metadata_array request_metadata_recv;
  grpc_byte_buffer* request_payload_recv = nullptr;
  grpc_call_details call_details;
  grpc_status_code status;
  grpc_call_error error;
  grpc_slice details;

  gpr_timespec deadline = five_seconds_from_now();
  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
                               grpc_slice_from_static_string("/foo"), nullptr,
                               deadline, nullptr);
  GPR_ASSERT(c);

  grpc_metadata_array_init(&initial_metadata_recv);
  grpc_metadata_array_init(&trailing_metadata_recv);
  grpc_metadata_array_init(&request_metadata_recv);
  grpc_call_details_init(&call_details);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->data.send_initial_metadata.metadata = nullptr;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_MESSAGE;
  op->data.send_message.send_message = request_payload;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_INITIAL_METADATA;
  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  op->data.recv_status_on_client.status = &status;
  op->data.recv_status_on_client.status_details = &details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  error =
      grpc_server_request_call(f.server, &s, &call_details,
                               &request_metadata_recv, f.cq, f.cq, tag(101));
  GPR_ASSERT(GRPC_CALL_OK == error);

  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
  cq_verify(cqv);

  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
  GPR_ASSERT(0 ==
             grpc_slice_str_cmp(details, "Failure that's not preventable."));

  grpc_slice_unref(details);
  grpc_metadata_array_destroy(&initial_metadata_recv);
  grpc_metadata_array_destroy(&trailing_metadata_recv);
  grpc_metadata_array_destroy(&request_metadata_recv);
  grpc_call_details_destroy(&call_details);

  grpc_call_unref(c);

  cq_verifier_destroy(cqv);

  grpc_byte_buffer_destroy(request_payload);
  grpc_byte_buffer_destroy(request_payload_recv);

  end_test(&f);
  config.tear_down_data(&f);
}

/*******************************************************************************
 * Test filter - always closes incoming requests
 */

typedef struct {
  grpc_closure* recv_im_ready;
} call_data;

typedef struct {
  uint8_t unused;
} channel_data;

static void recv_im_ready(void* arg, grpc_error* error) {
  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
  call_data* calld = static_cast<call_data*>(elem->call_data);
  GRPC_CLOSURE_RUN(
      calld->recv_im_ready,
      grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                             "Failure that's not preventable.", &error, 1),
                         GRPC_ERROR_INT_GRPC_STATUS,
                         GRPC_STATUS_PERMISSION_DENIED));
}

static void start_transport_stream_op_batch(
    grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
  call_data* calld = static_cast<call_data*>(elem->call_data);
  if (op->recv_initial_metadata) {
    calld->recv_im_ready =
        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
        GRPC_CLOSURE_CREATE(recv_im_ready, elem, grpc_schedule_on_exec_ctx);
  }
  grpc_call_next_op(elem, op);
}

static grpc_error* init_call_elem(grpc_call_element* elem,
                                  const grpc_call_element_args* args) {
  return GRPC_ERROR_NONE;
}

static void destroy_call_elem(grpc_call_element* elem,
                              const grpc_call_final_info* final_info,
                              grpc_closure* ignored) {}

static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                     grpc_channel_element_args* args) {
  return GRPC_ERROR_NONE;
}

static void destroy_channel_elem(grpc_channel_element* elem) {}

static const grpc_channel_filter test_filter = {
    start_transport_stream_op_batch,
    grpc_channel_next_op,
    sizeof(call_data),
    init_call_elem,
    grpc_call_stack_ignore_set_pollset_or_pollset_set,
    destroy_call_elem,
    sizeof(channel_data),
    init_channel_elem,
    destroy_channel_elem,
    grpc_channel_next_get_info,
    "filter_causes_close"};

/*******************************************************************************
 * Registration
 */

static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) {
  if (g_enable_filter) {
    return grpc_channel_stack_builder_prepend_filter(builder, &test_filter,
                                                     nullptr, nullptr);
  } else {
    return true;
  }
}

static void init_plugin(void) {
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, 0, maybe_add_filter,
                                   nullptr);
}

static void destroy_plugin(void) {}

void filter_causes_close(grpc_end2end_test_config config) {
  g_enable_filter = true;
  test_request(config);
  g_enable_filter = false;
}

void filter_causes_close_pre_init(void) {
  grpc_register_plugin(init_plugin, destroy_plugin);
}
<commit_msg>update test<commit_after>/*
 *
 * Copyright 2015 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 "test/core/end2end/end2end_tests.h"

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

#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/surface/channel_init.h"
#include "test/core/end2end/cq_verifier.h"

static bool g_enable_filter = false;

static void* tag(intptr_t t) { return (void*)t; }

static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
                                            const char* test_name,
                                            grpc_channel_args* client_args,
                                            grpc_channel_args* server_args) {
  grpc_end2end_test_fixture f;
  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
  f = config.create_fixture(client_args, server_args);
  config.init_server(&f, server_args);
  config.init_client(&f, client_args);
  return f;
}

static gpr_timespec n_seconds_from_now(int n) {
  return grpc_timeout_seconds_to_deadline(n);
}

static gpr_timespec five_seconds_from_now(void) {
  return n_seconds_from_now(5);
}

static void drain_cq(grpc_completion_queue* cq) {
  grpc_event ev;
  do {
    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
}

static void shutdown_server(grpc_end2end_test_fixture* f) {
  if (!f->server) return;
  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
                                         grpc_timeout_seconds_to_deadline(5),
                                         nullptr)
                 .type == GRPC_OP_COMPLETE);
  grpc_server_destroy(f->server);
  f->server = nullptr;
}

static void shutdown_client(grpc_end2end_test_fixture* f) {
  if (!f->client) return;
  grpc_channel_destroy(f->client);
  f->client = nullptr;
}

static void end_test(grpc_end2end_test_fixture* f) {
  shutdown_server(f);
  shutdown_client(f);

  grpc_completion_queue_shutdown(f->cq);
  drain_cq(f->cq);
  grpc_completion_queue_destroy(f->cq);
  grpc_completion_queue_destroy(f->shutdown_cq);
}

/* Simple request via a server filter that always closes the stream.*/
static void test_request(grpc_end2end_test_config config) {
  grpc_call* c;
  grpc_call* s;
  grpc_slice request_payload_slice =
      grpc_slice_from_copied_string("hello world");
  grpc_byte_buffer* request_payload =
      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
  grpc_end2end_test_fixture f =
      begin_test(config, "filter_causes_close", nullptr, nullptr);
  cq_verifier* cqv = cq_verifier_create(f.cq);
  grpc_op ops[6];
  grpc_op* op;
  grpc_metadata_array initial_metadata_recv;
  grpc_metadata_array trailing_metadata_recv;
  grpc_metadata_array request_metadata_recv;
  grpc_byte_buffer* request_payload_recv = nullptr;
  grpc_call_details call_details;
  grpc_status_code status;
  grpc_call_error error;
  grpc_slice details;

  gpr_timespec deadline = five_seconds_from_now();
  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
                               grpc_slice_from_static_string("/foo"), nullptr,
                               deadline, nullptr);
  GPR_ASSERT(c);

  grpc_metadata_array_init(&initial_metadata_recv);
  grpc_metadata_array_init(&trailing_metadata_recv);
  grpc_metadata_array_init(&request_metadata_recv);
  grpc_call_details_init(&call_details);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->data.send_initial_metadata.metadata = nullptr;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_MESSAGE;
  op->data.send_message.send_message = request_payload;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_INITIAL_METADATA;
  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  op->data.recv_status_on_client.status = &status;
  op->data.recv_status_on_client.status_details = &details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  error =
      grpc_server_request_call(f.server, &s, &call_details,
                               &request_metadata_recv, f.cq, f.cq, tag(101));
  GPR_ASSERT(GRPC_CALL_OK == error);

  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
  cq_verify(cqv);

  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
  GPR_ASSERT(0 ==
             grpc_slice_str_cmp(details, "Failure that's not preventable."));

  grpc_slice_unref(details);
  grpc_metadata_array_destroy(&initial_metadata_recv);
  grpc_metadata_array_destroy(&trailing_metadata_recv);
  grpc_metadata_array_destroy(&request_metadata_recv);
  grpc_call_details_destroy(&call_details);

  grpc_call_unref(c);

  cq_verifier_destroy(cqv);

  grpc_byte_buffer_destroy(request_payload);
  grpc_byte_buffer_destroy(request_payload_recv);

  end_test(&f);
  config.tear_down_data(&f);
}

/*******************************************************************************
 * Test filter - always closes incoming requests
 */

typedef struct {
  grpc_closure* recv_im_ready;
} call_data;

typedef struct {
  uint8_t unused;
} channel_data;

static void recv_im_ready(void* arg, grpc_error* error) {
  grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
  call_data* calld = static_cast<call_data*>(elem->call_data);
  GRPC_CLOSURE_RUN(
      calld->recv_im_ready,
      grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                             "Failure that's not preventable.", &error, 1),
                         GRPC_ERROR_INT_GRPC_STATUS,
                         GRPC_STATUS_PERMISSION_DENIED));
}

static void start_transport_stream_op_batch(
    grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
  call_data* calld = static_cast<call_data*>(elem->call_data);
  if (op->recv_initial_metadata) {
    calld->recv_im_ready =
        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
        GRPC_CLOSURE_CREATE(recv_im_ready, elem, grpc_schedule_on_exec_ctx);
  }
  grpc_call_next_op(elem, op);
}

static grpc_error* init_call_elem(grpc_call_element* elem,
                                  const grpc_call_element_args* args) {
  return GRPC_ERROR_NONE;
}

static void destroy_call_elem(grpc_call_element* elem,
                              const grpc_call_final_info* final_info,
                              grpc_closure* ignored) {}

static grpc_error* init_channel_elem(grpc_channel_element* elem,
                                     grpc_channel_element_args* args) {
  return GRPC_ERROR_NONE;
}

static void destroy_channel_elem(grpc_channel_element* elem) {}

static const grpc_channel_filter test_filter = {
    start_transport_stream_op_batch,
    grpc_channel_next_op,
    sizeof(call_data),
    init_call_elem,
    grpc_call_stack_ignore_set_pollset_or_pollset_set,
    destroy_call_elem,
    sizeof(channel_data),
    init_channel_elem,
    destroy_channel_elem,
    grpc_channel_next_get_info,
    "filter_causes_close"};

/*******************************************************************************
 * Registration
 */

static bool maybe_add_filter(grpc_channel_stack_builder* builder, void* arg) {
  if (g_enable_filter) {
    return grpc_channel_stack_builder_prepend_filter(builder, &test_filter,
                                                     nullptr, nullptr);
  } else {
    return true;
  }
}

static void init_plugin(void) {
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
                                   GRPC_CHANNEL_INIT_PRIORITY_HIGH,
                                   maybe_add_filter, nullptr);
}

static void destroy_plugin(void) {}

void filter_causes_close(grpc_end2end_test_config config) {
  g_enable_filter = true;
  test_request(config);
  g_enable_filter = false;
}

void filter_causes_close_pre_init(void) {
  grpc_register_plugin(init_plugin, destroy_plugin);
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

/** @file
 * @brief @ref compilation-speedup-hpp "Template implementation" for @ref ScreenedApplication.h and @ref Screen.h
 */

#include "Magnum/Platform/Screen.h"
#include "Magnum/Platform/ScreenedApplication.h"

namespace Magnum { namespace Platform {

template<class Application> BasicScreen<Application>::BasicScreen() = default;
template<class Application> BasicScreen<Application>::~BasicScreen() = default;

template<class Application> void BasicScreen<Application>::keyPressEvent(KeyEvent&) {}
template<class Application> void BasicScreen<Application>::keyReleaseEvent(KeyEvent&) {}
template<class Application> void BasicScreen<Application>::mousePressEvent(MouseEvent&) {}
template<class Application> void BasicScreen<Application>::mouseReleaseEvent(MouseEvent&) {}
template<class Application> void BasicScreen<Application>::mouseMoveEvent(MouseMoveEvent&) {}

template<class Application> BasicScreenedApplication<Application>::BasicScreenedApplication(const typename Application::Arguments& arguments, const typename Application::Configuration& configuration): Application(arguments, configuration) {}

template<class Application> BasicScreenedApplication<Application>::BasicScreenedApplication(const typename Application::Arguments& arguments, std::nullptr_t): Application(arguments, nullptr) {}

template<class Application> BasicScreenedApplication<Application>::~BasicScreenedApplication() = default;

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::addScreen(BasicScreen<Application>& screen) {
    Containers::LinkedList<BasicScreen<Application>>::insert(&screen);
    if(screens().first() == &screen) screen.focusEvent();
    Application::redraw();
    return *this;
}

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::removeScreen(BasicScreen<Application>& screen) {
    screen.blurEvent();
    Containers::LinkedList<BasicScreen<Application>>::erase(&screen);
    Application::redraw();
    return *this;
}

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::focusScreen(BasicScreen<Application>& screen) {
    /* Already focused, nothing to do */
    if(screens().first() == &screen) return *this;

    screens().first()->blurEvent();
    Containers::LinkedList<BasicScreen<Application>>::move(&screen, screens().first());
    screen.focusEvent();
    Application::redraw();
    return *this;
}

template<class Application> void BasicScreenedApplication<Application>::globalViewportEvent(const Vector2i&) {}

template<class Application> void BasicScreenedApplication<Application>::viewportEvent(const Vector2i& size) {
    /* Call viewport event after all other (because of framebuffer resizing) */
    globalViewportEvent(size);

    for(BasicScreen<Application>& s: *this) s.viewportEvent(size);
}

template<class Application> void BasicScreenedApplication<Application>::drawEvent() {
    /* Back-to-front rendering */
    for(BasicScreen<Application>* s = screens().last(); s; s = s->nextNearerScreen())
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Draw) s->drawEvent();

    /* Call global event after all other (because of buffer swapping) */
    globalDrawEvent();
}

template<class Application> void BasicScreenedApplication<Application>::keyPressEvent(typename Application::KeyEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->keyPressEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::keyReleaseEvent(typename Application::KeyEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->keyReleaseEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mousePressEvent(typename Application::MouseEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mousePressEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mouseReleaseEvent(typename Application::MouseEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mouseReleaseEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mouseMoveEvent(typename Application::MouseMoveEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mouseMoveEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

}}
<commit_msg>Platform: clarify comments.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

/** @file
 * @brief @ref compilation-speedup-hpp "Template implementation" for @ref ScreenedApplication.h and @ref Screen.h
 */

#include "Magnum/Platform/Screen.h"
#include "Magnum/Platform/ScreenedApplication.h"

namespace Magnum { namespace Platform {

template<class Application> BasicScreen<Application>::BasicScreen() = default;
template<class Application> BasicScreen<Application>::~BasicScreen() = default;

template<class Application> void BasicScreen<Application>::keyPressEvent(KeyEvent&) {}
template<class Application> void BasicScreen<Application>::keyReleaseEvent(KeyEvent&) {}
template<class Application> void BasicScreen<Application>::mousePressEvent(MouseEvent&) {}
template<class Application> void BasicScreen<Application>::mouseReleaseEvent(MouseEvent&) {}
template<class Application> void BasicScreen<Application>::mouseMoveEvent(MouseMoveEvent&) {}

template<class Application> BasicScreenedApplication<Application>::BasicScreenedApplication(const typename Application::Arguments& arguments, const typename Application::Configuration& configuration): Application(arguments, configuration) {}

template<class Application> BasicScreenedApplication<Application>::BasicScreenedApplication(const typename Application::Arguments& arguments, std::nullptr_t): Application(arguments, nullptr) {}

template<class Application> BasicScreenedApplication<Application>::~BasicScreenedApplication() = default;

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::addScreen(BasicScreen<Application>& screen) {
    Containers::LinkedList<BasicScreen<Application>>::insert(&screen);
    if(screens().first() == &screen) screen.focusEvent();
    Application::redraw();
    return *this;
}

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::removeScreen(BasicScreen<Application>& screen) {
    screen.blurEvent();
    Containers::LinkedList<BasicScreen<Application>>::erase(&screen);
    Application::redraw();
    return *this;
}

template<class Application> BasicScreenedApplication<Application>& BasicScreenedApplication<Application>::focusScreen(BasicScreen<Application>& screen) {
    /* Already focused, nothing to do */
    if(screens().first() == &screen) return *this;

    screens().first()->blurEvent();
    Containers::LinkedList<BasicScreen<Application>>::move(&screen, screens().first());
    screen.focusEvent();
    Application::redraw();
    return *this;
}

template<class Application> void BasicScreenedApplication<Application>::globalViewportEvent(const Vector2i&) {}

template<class Application> void BasicScreenedApplication<Application>::viewportEvent(const Vector2i& size) {
    /* Call global event before all other (to resize framebuffer first) */
    globalViewportEvent(size);

    for(BasicScreen<Application>& s: *this) s.viewportEvent(size);
}

template<class Application> void BasicScreenedApplication<Application>::drawEvent() {
    /* Back-to-front rendering */
    for(BasicScreen<Application>* s = screens().last(); s; s = s->nextNearerScreen())
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Draw) s->drawEvent();

    /* Call global event after all other (to swap buffers last) */
    globalDrawEvent();
}

template<class Application> void BasicScreenedApplication<Application>::keyPressEvent(typename Application::KeyEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->keyPressEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::keyReleaseEvent(typename Application::KeyEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->keyReleaseEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mousePressEvent(typename Application::MouseEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mousePressEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mouseReleaseEvent(typename Application::MouseEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mouseReleaseEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

template<class Application> void BasicScreenedApplication<Application>::mouseMoveEvent(typename Application::MouseMoveEvent& event) {
    /* Front-to-back event propagation, stop when the event gets accepted */
    for(BasicScreen<Application>* s = screens().first(); s; s = s->nextFartherScreen()) {
        if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
            s->mouseMoveEvent(event);
            if(event.isAccepted()) break;
        }
    }
}

}}
<|endoftext|>


<commit_before>/* OpenHoW
 * Copyright (C) 2017-2019 Mark Sowden <markelswo@gmail.com>
 *
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "../engine.h"
#include "../frontend.h"
#include "../audio.h"
#include "../Map.h"

#include "GameManager.h"
#include "SPGameMode.h"

GameManager *GameManager::instance_ = nullptr;

GameManager::GameManager() {

}

GameManager::~GameManager() {

}

void GameManager::Tick() {
    FrontEnd_Tick();

    if(active_mode_ == nullptr) {
        return;
    }

    if(ambient_emit_delay_ < g_state.sim_ticks) {
        const AudioSample* sample = ambient_samples_[rand() % MAX_AMBIENT_SAMPLES];
        u_assert(sample != nullptr, "Audio sample was unexpectedly freed!\n");

        float volume = 0.5f + (rand() % 10 / 1.0f);
        LogDebug("Volume: %f\n", volume);
        PLVector3 position = {
                static_cast<float>(rand() % MAP_PIXEL_WIDTH), 0,
                static_cast<float>(rand() % MAP_PIXEL_WIDTH)
        };

        AudioManager::GetInstance()->PlayLocalSound(sample, position, { 0, 0, 0 }, true, volume);
        ambient_emit_delay_ = g_state.sim_ticks + TICKS_PER_SECOND + rand() % (7 * TICKS_PER_SECOND);
    }

    active_mode_->Tick();
}

void GameManager::LoadMap(const std::string &name) {
    FrontEnd_SetState(FE_MODE_LOADING);

    if(active_map_ != nullptr) {

    }

    try {
        active_map_ = new Map(name);
    } catch(const std::runtime_error &e) {
        Error("Failed to load map, aborting!\n%s\n", e.what());
    }

    MapManifest* manifest = MapManager::GetInstance()->GetManifest(name);
    std::string sample_ext = "d";
    if(manifest->time != "day") {
        sample_ext = "n";
    }

    for(unsigned int i = 1, idx = 0; i < 4; ++i) {
        if(i < 3) {
            ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample(
                    "audio/amb_" + std::to_string(i) + sample_ext + ".wav", false);
        }
        ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample("audio/batt_s" + std::to_string(i) + ".wav", false);
        ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample("audio/batt_l" + std::to_string(i) + ".wav", false);
    }

    ambient_emit_delay_ = g_state.sim_ticks + rand() % 100;

    active_mode_ = new SPGameMode();
    // call StartRound; deals with spawning everything in and other mode specific logic
    active_mode_->StartRound();

    /* todo: we should actually pause here and wait for user input
     *       otherwise players won't have time to read the loading screen */
    FrontEnd_SetState(FE_MODE_GAME);
}

void GameManager::UnloadMap() {
    for(auto & ambient_sample : ambient_samples_) {
        delete ambient_sample;
    }

    delete active_mode_;
    delete active_map_;
}

Player* GameManager::GetCurrentPlayer() {
    if(active_mode_ == nullptr) {
        // todo: return local player... ?
        return nullptr;
    }

    return active_mode_->GetCurrentPlayer();
}
<commit_msg>ensure sounds are played at tallest level point + use GenerateRandomf rather than rand<commit_after>/* OpenHoW
 * Copyright (C) 2017-2019 Mark Sowden <markelswo@gmail.com>
 *
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "../engine.h"
#include "../frontend.h"
#include "../audio.h"
#include "../Map.h"

#include "GameManager.h"
#include "SPGameMode.h"

GameManager *GameManager::instance_ = nullptr;

GameManager::GameManager() {

}

GameManager::~GameManager() {

}

void GameManager::Tick() {
    FrontEnd_Tick();

    if(active_mode_ == nullptr) {
        return;
    }

    if(ambient_emit_delay_ < g_state.sim_ticks) {
        const AudioSample* sample = ambient_samples_[rand() % MAX_AMBIENT_SAMPLES];
        if(sample != nullptr) {
            PLVector3 position = {
                    plGenerateRandomf(MAP_PIXEL_WIDTH),
                    active_map_->GetMaxHeight(),
                    plGenerateRandomf(MAP_PIXEL_WIDTH)
            };
            AudioManager::GetInstance()->PlayLocalSound(sample, position, { 0, 0, 0 }, true, 0.5f);
        }

        ambient_emit_delay_ = g_state.sim_ticks + TICKS_PER_SECOND + rand() % (7 * TICKS_PER_SECOND);
    }

    active_mode_->Tick();
}

void GameManager::LoadMap(const std::string &name) {
    FrontEnd_SetState(FE_MODE_LOADING);

    if(active_map_ != nullptr) {

    }

    try {
        active_map_ = new Map(name);
    } catch(const std::runtime_error &e) {
        Error("Failed to load map, aborting!\n%s\n", e.what());
    }

    MapManifest* manifest = MapManager::GetInstance()->GetManifest(name);
    std::string sample_ext = "d";
    if(manifest->time != "day") {
        sample_ext = "n";
    }

    for(unsigned int i = 1, idx = 0; i < 4; ++i) {
        if(i < 3) {
            ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample(
                    "audio/amb_" + std::to_string(i) + sample_ext + ".wav", false);
        }
        ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample("audio/batt_s" + std::to_string(i) + ".wav", false);
        ambient_samples_[idx++] = AudioManager::GetInstance()->CacheSample("audio/batt_l" + std::to_string(i) + ".wav", false);
    }

    ambient_emit_delay_ = g_state.sim_ticks + rand() % 100;

    active_mode_ = new SPGameMode();
    // call StartRound; deals with spawning everything in and other mode specific logic
    active_mode_->StartRound();

    /* todo: we should actually pause here and wait for user input
     *       otherwise players won't have time to read the loading screen */
    FrontEnd_SetState(FE_MODE_GAME);
}

void GameManager::UnloadMap() {
    for(auto & ambient_sample : ambient_samples_) {
        delete ambient_sample;
    }

    delete active_mode_;
    delete active_map_;
}

Player* GameManager::GetCurrentPlayer() {
    if(active_mode_ == nullptr) {
        // todo: return local player... ?
        return nullptr;
    }

    return active_mode_->GetCurrentPlayer();
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <utility>
#include <Nazara/Graphics/Debug.hpp>

namespace Nz
{
	SpriteChainRenderer::SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize) :
	m_device(device),
	m_maxVertexBufferSize(maxVertexBufferSize),
	m_maxVertexCount(m_maxVertexBufferSize / (2 * sizeof(float))) // Treat vec2 as the minimum declaration possible
	{
		m_vertexBufferPool = std::make_shared<VertexBufferPool>();

		std::size_t maxQuadCount = m_maxVertexCount / 4;
		std::size_t indexCount = 6 * maxQuadCount;

		m_indexBuffer = m_device.InstantiateBuffer(BufferType::Index);
		if (!m_indexBuffer->Initialize(indexCount * sizeof(UInt16), BufferUsage::DeviceLocal))
			throw std::runtime_error("failed to initialize index buffer");

		// Generate indices for quad (0, 1, 2, 2, 1, 3, ...)
		std::vector<UInt16> indices(indexCount);
		UInt16* indexPtr = indices.data();

		for (std::size_t i = 0; i < maxQuadCount; ++i)
		{
			*indexPtr++ = i * 4 + 0;
			*indexPtr++ = i * 4 + 1;
			*indexPtr++ = i * 4 + 2;

			*indexPtr++ = i * 4 + 2;
			*indexPtr++ = i * 4 + 1;
			*indexPtr++ = i * 4 + 3;
		}

		m_indexBuffer->Fill(indices.data(), 0, indexCount * sizeof(UInt16));
	}

	std::unique_ptr<ElementRendererData> SpriteChainRenderer::InstanciateData()
	{
		return std::make_unique<SpriteChainRendererData>();
	}

	void SpriteChainRenderer::Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount)
	{
		Graphics* graphics = Graphics::Instance();

		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		std::size_t firstQuadIndex = 0;
		SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
		UploadPool::Allocation* currentAllocation = nullptr;
		UInt8* currentAllocationMemPtr = nullptr;
		const VertexDeclaration* currentVertexDeclaration = nullptr;
		AbstractBuffer* currentVertexBuffer = nullptr;
		const RenderPipeline* currentPipeline = nullptr;
		const ShaderBinding* currentDrawDataBinding = nullptr;
		const ShaderBinding* currentInstanceBinding = nullptr;
		const ShaderBinding* currentMaterialBinding = nullptr;
		const Texture* currentTextureOverlay = nullptr;

		auto FlushDrawCall = [&]()
		{
			currentDrawCall = nullptr;
		};

		auto FlushDrawData = [&]()
		{
			FlushDrawCall();

			currentDrawDataBinding = nullptr;
		};

		auto Flush = [&]()
		{
			// changing vertex buffer always mean we have to switch draw calls
			FlushDrawCall();

			if (currentAllocation)
			{
				m_pendingCopies.emplace_back(currentAllocation, currentVertexBuffer);

				firstQuadIndex = 0;
				currentAllocation = nullptr;
				currentVertexBuffer = nullptr;
			}
		};

		std::size_t oldDrawCallCount = data.drawCalls.size();
		const auto& defaultSampler = graphics->GetSamplerCache().Get({});

		for (std::size_t i = 0; i < elementCount; ++i)
		{
			assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain));
			const RenderSpriteChain& spriteChain = static_cast<const RenderSpriteChain&>(*elements[i]);

			const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration();
			std::size_t stride = vertexDeclaration->GetStride();

			if (currentVertexDeclaration != vertexDeclaration)
			{
				// TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated
				// Wait until buffer rewrite
				Flush();
				currentVertexDeclaration = vertexDeclaration;
			}

			if (currentPipeline != spriteChain.GetRenderPipeline())
			{
				FlushDrawCall();
				currentPipeline = spriteChain.GetRenderPipeline();
			}

			if (currentMaterialBinding != &spriteChain.GetMaterialBinding())
			{
				FlushDrawCall();
				currentMaterialBinding = &spriteChain.GetMaterialBinding();
			}

			if (currentInstanceBinding != &spriteChain.GetInstanceBinding())
			{
				// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
				// which is far from being efficient, using some bindless could help (or at least instancing?)
				FlushDrawCall();
				currentInstanceBinding = &spriteChain.GetInstanceBinding();
			}

			if (currentTextureOverlay != spriteChain.GetTextureOverlay())
			{
				FlushDrawData();
				currentTextureOverlay = spriteChain.GetTextureOverlay();
			}

			std::size_t remainingQuads = spriteChain.GetSpriteCount();
			while (remainingQuads > 0)
			{
				if (!currentAllocation)
				{
					currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
					currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);

					std::shared_ptr<AbstractBuffer> vertexBuffer;

					// Try to reuse vertex buffers from pool if any
					if (!m_vertexBufferPool->vertexBuffers.empty())
					{
						vertexBuffer = std::move(m_vertexBufferPool->vertexBuffers.back());
						m_vertexBufferPool->vertexBuffers.pop_back();
					}
					else
					{
						vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex);
						vertexBuffer->Initialize(m_maxVertexBufferSize, BufferUsage::DeviceLocal);
					}

					currentVertexBuffer = vertexBuffer.get();

					data.vertexBuffers.emplace_back(std::move(vertexBuffer));
				}

				if (!currentDrawDataBinding)
				{
					ShaderBindingPtr drawDataBinding = Graphics::Instance()->GetReferencePipelineLayout()->AllocateShaderBinding(Graphics::DrawDataBindingSet);
					drawDataBinding->Update({
						{
							0,
							ShaderBinding::TextureBinding {
								currentTextureOverlay, defaultSampler.get()
							}
						}
					});

					currentDrawDataBinding = drawDataBinding.get();

					data.shaderBindings.emplace_back(std::move(drawDataBinding));
				}

				if (!currentDrawCall)
				{
					data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
						currentVertexBuffer,
						currentPipeline,
						currentDrawDataBinding,
						currentInstanceBinding,
						currentMaterialBinding,
						6 * firstQuadIndex,
						0,
					});

					currentDrawCall = &data.drawCalls.back();
				}

				std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr));
				std::size_t maxQuads = remainingSpace / (4 * stride);
				if (maxQuads == 0)
				{
					Flush();
					continue;
				}

				std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads);
				std::size_t copiedSize = 4 * copiedQuadCount * stride;

				std::memcpy(currentAllocationMemPtr, spriteChain.GetSpriteData(), copiedSize);
				currentAllocationMemPtr += copiedSize;

				firstQuadIndex += copiedQuadCount;
				currentDrawCall->quadCount += copiedQuadCount;
				remainingQuads -= copiedQuadCount;

				// If there's still data to copy, it means buffer is full, flush it
				if (remainingQuads > 0)
					Flush();
			}
		}

		//TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls
		Flush();

		const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
		std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
		data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };

		if (!m_pendingCopies.empty())
		{
			currentFrame.Execute([&](CommandBufferBuilder& builder)
			{
				for (auto&& [allocation, buffer] : m_pendingCopies)
					builder.CopyBuffer(*allocation, buffer);

				builder.PostTransferBarrier();
			}, Nz::QueueType::Transfer);

			m_pendingCopies.clear();
		}
	}

	void SpriteChainRenderer::Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
	{
		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		commandBuffer.BindIndexBuffer(*m_indexBuffer);

		const AbstractBuffer* currentVertexBuffer = nullptr;
		const RenderPipeline* currentPipeline = nullptr;
		const ShaderBinding* currentDrawDataBinding = nullptr;
		const ShaderBinding* currentInstanceBinding = nullptr;
		const ShaderBinding* currentMaterialBinding = nullptr;

		const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
		auto it = data.drawCallPerElement.find(firstSpriteChain);
		assert(it != data.drawCallPerElement.end());

		const auto& indices = it->second;

		for (std::size_t i = 0; i < indices.count; ++i)
		{
			const auto& drawCall = data.drawCalls[indices.start + i];

			if (currentVertexBuffer != drawCall.vertexBuffer)
			{
				commandBuffer.BindVertexBuffer(0, *drawCall.vertexBuffer);
				currentVertexBuffer = drawCall.vertexBuffer;
			}

			if (currentPipeline != drawCall.renderPipeline)
			{
				commandBuffer.BindPipeline(*drawCall.renderPipeline);
				currentPipeline = drawCall.renderPipeline;
			}

			if (currentDrawDataBinding != drawCall.drawDataBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::DrawDataBindingSet, *drawCall.drawDataBinding);
				currentDrawDataBinding = drawCall.drawDataBinding;
			}

			if (currentMaterialBinding != drawCall.materialBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, *drawCall.materialBinding);
				currentMaterialBinding = drawCall.materialBinding;
			}

			if (currentInstanceBinding != drawCall.instanceBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::WorldBindingSet, *drawCall.instanceBinding);
				currentInstanceBinding = drawCall.instanceBinding;
			}

			commandBuffer.DrawIndexed(drawCall.quadCount * 6, 1U, drawCall.firstIndex);
		}
	}

	void SpriteChainRenderer::Reset(ElementRendererData& rendererData, RenderFrame& currentFrame)
	{
		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		for (auto& vertexBufferPtr : data.vertexBuffers)
		{
			currentFrame.PushReleaseCallback([pool = m_vertexBufferPool, vertexBuffer = std::move(vertexBufferPtr)]()
			{
				pool->vertexBuffers.push_back(std::move(vertexBuffer));
			});
		}
		data.vertexBuffers.clear();

		for (auto& shaderBinding : data.shaderBindings)
			currentFrame.PushForRelease(std::move(shaderBinding));
		data.shaderBindings.clear();

		data.drawCalls.clear();
	}
}
<commit_msg>Graphics/SpriteChainRenderer: Fix single sprite data over multiple vertex buffers<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <utility>
#include <Nazara/Graphics/Debug.hpp>

namespace Nz
{
	SpriteChainRenderer::SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize) :
	m_device(device),
	m_maxVertexBufferSize(maxVertexBufferSize),
	m_maxVertexCount(m_maxVertexBufferSize / (2 * sizeof(float))) // Treat vec2 as the minimum declaration possible
	{
		m_vertexBufferPool = std::make_shared<VertexBufferPool>();

		std::size_t maxQuadCount = m_maxVertexCount / 4;
		std::size_t indexCount = 6 * maxQuadCount;

		m_indexBuffer = m_device.InstantiateBuffer(BufferType::Index);
		if (!m_indexBuffer->Initialize(indexCount * sizeof(UInt16), BufferUsage::DeviceLocal))
			throw std::runtime_error("failed to initialize index buffer");

		// Generate indices for quad (0, 1, 2, 2, 1, 3, ...)
		std::vector<UInt16> indices(indexCount);
		UInt16* indexPtr = indices.data();

		for (std::size_t i = 0; i < maxQuadCount; ++i)
		{
			*indexPtr++ = i * 4 + 0;
			*indexPtr++ = i * 4 + 1;
			*indexPtr++ = i * 4 + 2;

			*indexPtr++ = i * 4 + 2;
			*indexPtr++ = i * 4 + 1;
			*indexPtr++ = i * 4 + 3;
		}

		m_indexBuffer->Fill(indices.data(), 0, indexCount * sizeof(UInt16));
	}

	std::unique_ptr<ElementRendererData> SpriteChainRenderer::InstanciateData()
	{
		return std::make_unique<SpriteChainRendererData>();
	}

	void SpriteChainRenderer::Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount)
	{
		Graphics* graphics = Graphics::Instance();

		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		std::size_t firstQuadIndex = 0;
		SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
		UploadPool::Allocation* currentAllocation = nullptr;
		UInt8* currentAllocationMemPtr = nullptr;
		const VertexDeclaration* currentVertexDeclaration = nullptr;
		AbstractBuffer* currentVertexBuffer = nullptr;
		const RenderPipeline* currentPipeline = nullptr;
		const ShaderBinding* currentDrawDataBinding = nullptr;
		const ShaderBinding* currentInstanceBinding = nullptr;
		const ShaderBinding* currentMaterialBinding = nullptr;
		const Texture* currentTextureOverlay = nullptr;

		auto FlushDrawCall = [&]()
		{
			currentDrawCall = nullptr;
		};

		auto FlushDrawData = [&]()
		{
			FlushDrawCall();

			currentDrawDataBinding = nullptr;
		};

		auto Flush = [&]()
		{
			// changing vertex buffer always mean we have to switch draw calls
			FlushDrawCall();

			if (currentAllocation)
			{
				m_pendingCopies.emplace_back(currentAllocation, currentVertexBuffer);

				firstQuadIndex = 0;
				currentAllocation = nullptr;
				currentVertexBuffer = nullptr;
			}
		};

		std::size_t oldDrawCallCount = data.drawCalls.size();
		const auto& defaultSampler = graphics->GetSamplerCache().Get({});

		for (std::size_t i = 0; i < elementCount; ++i)
		{
			assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain));
			const RenderSpriteChain& spriteChain = static_cast<const RenderSpriteChain&>(*elements[i]);

			const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration();
			std::size_t stride = vertexDeclaration->GetStride();

			if (currentVertexDeclaration != vertexDeclaration)
			{
				// TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated
				// Wait until buffer rewrite
				Flush();
				currentVertexDeclaration = vertexDeclaration;
			}

			if (currentPipeline != spriteChain.GetRenderPipeline())
			{
				FlushDrawCall();
				currentPipeline = spriteChain.GetRenderPipeline();
			}

			if (currentMaterialBinding != &spriteChain.GetMaterialBinding())
			{
				FlushDrawCall();
				currentMaterialBinding = &spriteChain.GetMaterialBinding();
			}

			if (currentInstanceBinding != &spriteChain.GetInstanceBinding())
			{
				// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
				// which is far from being efficient, using some bindless could help (or at least instancing?)
				FlushDrawCall();
				currentInstanceBinding = &spriteChain.GetInstanceBinding();
			}

			if (currentTextureOverlay != spriteChain.GetTextureOverlay())
			{
				FlushDrawData();
				currentTextureOverlay = spriteChain.GetTextureOverlay();
			}

			std::size_t remainingQuads = spriteChain.GetSpriteCount();
			const UInt8* spriteData = static_cast<const UInt8*>(spriteChain.GetSpriteData());

			while (remainingQuads > 0)
			{
				if (!currentAllocation)
				{
					currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
					currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);

					std::shared_ptr<AbstractBuffer> vertexBuffer;

					// Try to reuse vertex buffers from pool if any
					if (!m_vertexBufferPool->vertexBuffers.empty())
					{
						vertexBuffer = std::move(m_vertexBufferPool->vertexBuffers.back());
						m_vertexBufferPool->vertexBuffers.pop_back();
					}
					else
					{
						vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex);
						vertexBuffer->Initialize(m_maxVertexBufferSize, BufferUsage::DeviceLocal);
					}

					currentVertexBuffer = vertexBuffer.get();

					data.vertexBuffers.emplace_back(std::move(vertexBuffer));
				}

				if (!currentDrawDataBinding)
				{
					ShaderBindingPtr drawDataBinding = Graphics::Instance()->GetReferencePipelineLayout()->AllocateShaderBinding(Graphics::DrawDataBindingSet);
					drawDataBinding->Update({
						{
							0,
							ShaderBinding::TextureBinding {
								currentTextureOverlay, defaultSampler.get()
							}
						}
					});

					currentDrawDataBinding = drawDataBinding.get();

					data.shaderBindings.emplace_back(std::move(drawDataBinding));
				}

				if (!currentDrawCall)
				{
					data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
						currentVertexBuffer,
						currentPipeline,
						currentDrawDataBinding,
						currentInstanceBinding,
						currentMaterialBinding,
						6 * firstQuadIndex,
						0,
					});

					currentDrawCall = &data.drawCalls.back();
				}

				std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr));
				std::size_t maxQuads = remainingSpace / (4 * stride);
				if (maxQuads == 0)
				{
					Flush();
					continue;
				}

				std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads);
				std::size_t copiedSize = 4 * copiedQuadCount * stride;

				std::memcpy(currentAllocationMemPtr, spriteData, copiedSize);
				currentAllocationMemPtr += copiedSize;
				spriteData += copiedSize;

				firstQuadIndex += copiedQuadCount;
				currentDrawCall->quadCount += copiedQuadCount;
				remainingQuads -= copiedQuadCount;

				// If there's still data to copy, it means buffer is full, flush it
				if (remainingQuads > 0)
					Flush();
			}
		}

		//TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls
		Flush();

		const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
		std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
		data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };

		if (!m_pendingCopies.empty())
		{
			currentFrame.Execute([&](CommandBufferBuilder& builder)
			{
				for (auto&& [allocation, buffer] : m_pendingCopies)
					builder.CopyBuffer(*allocation, buffer);

				builder.PostTransferBarrier();
			}, Nz::QueueType::Transfer);

			m_pendingCopies.clear();
		}
	}

	void SpriteChainRenderer::Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
	{
		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		commandBuffer.BindIndexBuffer(*m_indexBuffer);

		const AbstractBuffer* currentVertexBuffer = nullptr;
		const RenderPipeline* currentPipeline = nullptr;
		const ShaderBinding* currentDrawDataBinding = nullptr;
		const ShaderBinding* currentInstanceBinding = nullptr;
		const ShaderBinding* currentMaterialBinding = nullptr;

		const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
		auto it = data.drawCallPerElement.find(firstSpriteChain);
		assert(it != data.drawCallPerElement.end());

		const auto& indices = it->second;

		for (std::size_t i = 0; i < indices.count; ++i)
		{
			const auto& drawCall = data.drawCalls[indices.start + i];

			if (currentVertexBuffer != drawCall.vertexBuffer)
			{
				commandBuffer.BindVertexBuffer(0, *drawCall.vertexBuffer);
				currentVertexBuffer = drawCall.vertexBuffer;
			}

			if (currentPipeline != drawCall.renderPipeline)
			{
				commandBuffer.BindPipeline(*drawCall.renderPipeline);
				currentPipeline = drawCall.renderPipeline;
			}

			if (currentDrawDataBinding != drawCall.drawDataBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::DrawDataBindingSet, *drawCall.drawDataBinding);
				currentDrawDataBinding = drawCall.drawDataBinding;
			}

			if (currentMaterialBinding != drawCall.materialBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, *drawCall.materialBinding);
				currentMaterialBinding = drawCall.materialBinding;
			}

			if (currentInstanceBinding != drawCall.instanceBinding)
			{
				commandBuffer.BindShaderBinding(Graphics::WorldBindingSet, *drawCall.instanceBinding);
				currentInstanceBinding = drawCall.instanceBinding;
			}

			commandBuffer.DrawIndexed(drawCall.quadCount * 6, 1U, drawCall.firstIndex);
		}
	}

	void SpriteChainRenderer::Reset(ElementRendererData& rendererData, RenderFrame& currentFrame)
	{
		auto& data = static_cast<SpriteChainRendererData&>(rendererData);

		for (auto& vertexBufferPtr : data.vertexBuffers)
		{
			currentFrame.PushReleaseCallback([pool = m_vertexBufferPool, vertexBuffer = std::move(vertexBufferPtr)]()
			{
				pool->vertexBuffers.push_back(std::move(vertexBuffer));
			});
		}
		data.vertexBuffers.clear();

		for (auto& shaderBinding : data.shaderBindings)
			currentFrame.PushForRelease(std::move(shaderBinding));
		data.shaderBindings.clear();

		data.drawCalls.clear();
	}
}
<|endoftext|>