<commit_before>/**
 *  @author Blurred-9L
 *  @file   Tokenizer.cpp
 */

#include "Tokenizer.h"
#include "AbstractAutomata.h"
#include "KeywordSet.h"

#include "../Core/Token.h"
#include "../Core/LineFileReader.h"
#include "../Core/ErrorKeeper.h"

/**
 *  @details    Constructs a Tokenizer object. The object constructed
 *              does not have a set automata, keyword set or line reader,
 *              so the user should remember to set them before calling
 *              getToken().
 */
Tokenizer::Tokenizer() :
    automata_(0), keywords_(0), lineReader_(0), errorKeeper_(0), line_(),
    charIdx(-1), tokenStartIndex(-1), tokenLineNumber_(0)
{
}

/**
 *  @details    Constructs a Tokenizer object with the given automata,
 *              keyword set and line reader.
 *
 *  @param[in]  automata        The automata to use. Should be dynamically
 *                              allocated.
 *  @param[in]  keywords        The keyword set to use. Should be dynamically
 *                              allocated.
 *  @param[in]  lineReader      The lineReader set to use. Should be dynamically
 *                              allocated.
 *  @param[in]  errorKeeper     The errorKeeper set to use. Should be dynamically
 *                              allocated.
 */
Tokenizer::Tokenizer(AbstractAutomata * automata, KeywordSet * keywords,
                     LineFileReader * lineReader, ErrorKeeper * errorKeeper) :
    automata_(automata), keywords_(keywords), lineReader_(lineReader),
    errorKeeper_(errorKeeper), line_(), charIdx(-1), tokenStartIndex(-1)
{
}

/**
 *  @details    Destroys the Tokenizer object.
 */
Tokenizer::~Tokenizer()
{
    if (automata_ != 0) {
        delete automata_;
    }
    if (keywords_ != 0) {
        delete keywords_;
    }
    if (lineReader_ != 0) {
        delete lineReader_;
    }
    if (errorKeeper_ != 0) {
        delete errorKeeper_;
    }
}

/**
 *  @details    Gets the automata attribute from the Tokenizer.
 *
 *  @return     A constant reference to the automata attribute.
 */
const AbstractAutomata & Tokenizer::automata() const
{
    return *automata_;
}

/**
 *  @details    Gets the automata attribute from the Tokenizer.
 *
 *  @return     A reference to the automata attribute.
 */
AbstractAutomata & Tokenizer::automata()
{
    return *automata_;
}

/**
 *  @details    Gets the keywords attribute from the Tokenizer.
 *
 *  @return     A constant reference to the keywords attribute.
 */
const KeywordSet & Tokenizer::keywords() const
{
    return *keywords_;
}

/**
 *  @details    Gets the keywords attribute from the Tokenizer.
 *
 *  @return     A reference to the keywords attribute.
 */
KeywordSet & Tokenizer::keywords()
{
    return *keywords_;
}

/**
 *  @details    Gets the lineReader attribute from the Tokenizer.
 *
 *  @return     A constant pointer to the lineReader attribute.
 */
const LineFileReader * Tokenizer::lineReader() const
{
    return lineReader_;
}

/**
 *  @details    Gets the lineReader attribute from the Tokenizer.
 *
 *  @return     A pointer to the lineReader attribute.
 */
LineFileReader * Tokenizer::lineReader()
{
    return lineReader_;
}

/**
 *  @details    Gets the errorKeeper attribute from the Tokenizer.
 *
 *  @return     A constant pointer to the errorKeeper attribute.
 */
const ErrorKeeper * Tokenizer::errorKeeper() const
{
    return errorKeeper_;
}

/**
 *  @details    Gets the errorKeeper attribute from the Tokenizer.
 *
 *  @return     A pointer to the errorKeeper attribute.
 */
ErrorKeeper * Tokenizer::errorKeeper()
{
    return errorKeeper_;
}

/**
 *  @details    Gets the tokenLineNumber attribute of the tokenizer.
 *
 *  @return     The value of the tokenLineNumber attribute.
 */
int Tokenizer::tokenLineNumber() const
{
    return tokenLineNumber_;
}

/**
 *  @details    Sets the automata to be used when tokenizing
 *              the given input string. The automata passed
 *              should be dynamically allocated. If a previous
 *              automata had been set, it will be deleted.
 *
 *  @param[in]  automata        The automata to use.
 */
void Tokenizer::setAutomata(AbstractAutomata * automata)
{
    if (automata != 0) {
        if (automata_ != 0) {
            delete automata_;
        }
        automata_ = automata;
    }
}

/**
 *  @details    Sets the keyword set to be used when tokenizing
 *              the given input string. The keyword set passed
 *              should have been dynamically allocated. If a
 *              previous keyword set had been set, it will be
 *              deleted.
 *
 *  @param[in]  keywords        The keyword set to use.
 */
void Tokenizer::setKeywords(KeywordSet * keywords)
{
    if (keywords != 0) {
        if (keywords_ != 0) {
            delete keywords_;
        }
        keywords_ = keywords;
    }
}

/**
 *  @details    Sets the line reader to be used when this tokenizer
 *              consumes a line. The lineReader passed should have
 *              been dynamically allocated. If a previous line reader
 *              had been set, it will be deleted. Since the line reader
 *              is not strictly necessary for the Tokenizer to
 *              function properly, it can be set to a 0 value.
 *
 *  @param[in]  lineReader      The lineReader to use.
 */
void Tokenizer::setLineReader(LineFileReader * lineReader)
{
    if (lineReader_ != 0) {
        delete lineReader_;
    }
    lineReader_ = lineReader;
}

/**
 *  @details    Sets the error keeper to be used whenever an error is
 *              raised by this tokenizer. The errorKeeper passed should
 *              have been dynamically allocated. If a previous error keeper
 *              had been set, it will be deleted. Since the error keeper
 *              is not strictly necessary for the Tokenizer to
 *              function properly, it can be set to a 0 value.
 *
 *  @param[in]  errorKeeper     The errorKeeper to use.
 */
void Tokenizer::setErrorKeeper(ErrorKeeper * errorKeeper)
{
    if (errorKeeper_ != 0) {
        delete errorKeeper_;
    }
    errorKeeper_ = errorKeeper;
}

/**
 *  @details    Sets the line to use when tokenizing and also
 *              resets the index used when iterating over it.
 *
 *  @param[in]  line            The line to be tokenized.
 */
void Tokenizer::setLine(const string & line)
{
    line_ = line;
    charIdx = 0;
}

/**
 *  @details    Sets the line number on which the given tokens
 *              were found.
 *
 *  @param[in]  tokenLineNumber The line number.
 */
void Tokenizer::setTokenLineNumber(int tokenLineNumber)
{
    tokenLineNumber_ = tokenLineNumber;
}

/**
 *  @details    Gets the next token from the given input string.
 *              The token returned will be dynamically allocated,
 *              so one should remember to deallocate it later.
 *
 *  @return     The token found or 0 if no more tokens can be
 *              extracted.
 */
Token * Tokenizer::getToken()
{
    Token * token = 0;
    string symbol;
    int lastState;

    if (lineReader_ != 0) {
        while (charIdx >= line_.length() && lineReader_->hasNext()) {
            lineReader_->sendNextLine(*this);
        }
    }

    if ((charIdx < line_.length()) && (automata_ != 0) && (keywords_ != 0)) {
        lastState = getTokenString(symbol);
        if (keywords_->isKeyword(symbol)) {
            token = new Token(keywords_->getKeywordId(symbol), tokenStartIndex,
                              tokenLineNumber_, symbol);
        } else if (automata_->isAcceptState(lastState)) {
            token = new Token(automata_->getTokenType(lastState), tokenStartIndex,
                              tokenLineNumber_, symbol);
        }
    }

    return token;
}

/**
 *  @details    Checks if an error has ocurred during the execution
 *              of the tokenizer.
 *
 *  @return     A boolean value indicating if an error has occur.
 */
bool Tokenizer::hasError() const
{
    bool errorExists = false;

    if (errorKeeper_ != 0) {
        errorExists = errorKeeper_->hasError();
    }

    return errorExists;
}

/////////////
// Private //
/////////////

/**
 *  @details    Algorithm used to build the substring of the
 *              input string to be included on the next token.
 *
 *  @param[out]  symbol          The string on which to copy the token's symbol.
 *
 *  @return     Returns the state at which the algorithm stopped. If
 *              an error ocurred, -1 is returned. If the algorithm
 *              stopped because the end of the string was reached
 *              before a full token was found, the last state is
 *              returned.
 */
int Tokenizer::getTokenString(string & symbol)
{
    int state = 0;
    unsigned lineLength = line_.length();
    bool done = false;
    bool error = false;
    bool gotFirstChar = false;

    while ((!done) && (!error) && (charIdx < lineLength)) {
        state = automata_->nextState(state, line_[charIdx]);
        if (state > 0) {
            if (!gotFirstChar) {
                gotFirstChar = true;
                tokenStartIndex = charIdx;
            }
            symbol.push_back(line_[charIdx]);
            if (automata_->isAcceptState(state)) {
                if (!automata_->includeNextChar(state, line_, charIdx)) {
                    done = true;
                }
            }
        } else if (state < 0) {
            error = true;
        }
        charIdx++;
    }

    if (error) {
        if (errorKeeper_ != 0) {
            errorKeeper_->addError(LEXIC_INPUT_ERROR, "Lexic Error: Wrong token formation | Unexpected symbol.");
        }
    } else if (!done) {
        if (errorKeeper_ != 0) {
            errorKeeper_->addError(TOKEN_NO_END_ERROR, "Lexic Error: Could not finish building last token.");
        }
    }

    return state;
}
<commit_msg>Fixes bug where whitespace only lines caused Tokenizer to fail.<commit_after>/**
 *  @author Blurred-9L
 *  @file   Tokenizer.cpp
 */

#include "Tokenizer.h"
#include "AbstractAutomata.h"
#include "KeywordSet.h"

#include "../Core/Token.h"
#include "../Core/LineFileReader.h"
#include "../Core/ErrorKeeper.h"

#include <cctype>

/**
 *  @details    Constructs a Tokenizer object. The object constructed
 *              does not have a set automata, keyword set or line reader,
 *              so the user should remember to set them before calling
 *              getToken().
 */
Tokenizer::Tokenizer() :
    automata_(0), keywords_(0), lineReader_(0), errorKeeper_(0), line_(),
    charIdx(-1), tokenStartIndex(-1), tokenLineNumber_(0)
{
}

/**
 *  @details    Constructs a Tokenizer object with the given automata,
 *              keyword set and line reader.
 *
 *  @param[in]  automata        The automata to use. Should be dynamically
 *                              allocated.
 *  @param[in]  keywords        The keyword set to use. Should be dynamically
 *                              allocated.
 *  @param[in]  lineReader      The lineReader set to use. Should be dynamically
 *                              allocated.
 *  @param[in]  errorKeeper     The errorKeeper set to use. Should be dynamically
 *                              allocated.
 */
Tokenizer::Tokenizer(AbstractAutomata * automata, KeywordSet * keywords,
                     LineFileReader * lineReader, ErrorKeeper * errorKeeper) :
    automata_(automata), keywords_(keywords), lineReader_(lineReader),
    errorKeeper_(errorKeeper), line_(), charIdx(-1), tokenStartIndex(-1)
{
}

/**
 *  @details    Destroys the Tokenizer object.
 */
Tokenizer::~Tokenizer()
{
    if (automata_ != 0) {
        delete automata_;
    }
    if (keywords_ != 0) {
        delete keywords_;
    }
    if (lineReader_ != 0) {
        delete lineReader_;
    }
    if (errorKeeper_ != 0) {
        delete errorKeeper_;
    }
}

/**
 *  @details    Gets the automata attribute from the Tokenizer.
 *
 *  @return     A constant reference to the automata attribute.
 */
const AbstractAutomata & Tokenizer::automata() const
{
    return *automata_;
}

/**
 *  @details    Gets the automata attribute from the Tokenizer.
 *
 *  @return     A reference to the automata attribute.
 */
AbstractAutomata & Tokenizer::automata()
{
    return *automata_;
}

/**
 *  @details    Gets the keywords attribute from the Tokenizer.
 *
 *  @return     A constant reference to the keywords attribute.
 */
const KeywordSet & Tokenizer::keywords() const
{
    return *keywords_;
}

/**
 *  @details    Gets the keywords attribute from the Tokenizer.
 *
 *  @return     A reference to the keywords attribute.
 */
KeywordSet & Tokenizer::keywords()
{
    return *keywords_;
}

/**
 *  @details    Gets the lineReader attribute from the Tokenizer.
 *
 *  @return     A constant pointer to the lineReader attribute.
 */
const LineFileReader * Tokenizer::lineReader() const
{
    return lineReader_;
}

/**
 *  @details    Gets the lineReader attribute from the Tokenizer.
 *
 *  @return     A pointer to the lineReader attribute.
 */
LineFileReader * Tokenizer::lineReader()
{
    return lineReader_;
}

/**
 *  @details    Gets the errorKeeper attribute from the Tokenizer.
 *
 *  @return     A constant pointer to the errorKeeper attribute.
 */
const ErrorKeeper * Tokenizer::errorKeeper() const
{
    return errorKeeper_;
}

/**
 *  @details    Gets the errorKeeper attribute from the Tokenizer.
 *
 *  @return     A pointer to the errorKeeper attribute.
 */
ErrorKeeper * Tokenizer::errorKeeper()
{
    return errorKeeper_;
}

/**
 *  @details    Gets the tokenLineNumber attribute of the tokenizer.
 *
 *  @return     The value of the tokenLineNumber attribute.
 */
int Tokenizer::tokenLineNumber() const
{
    return tokenLineNumber_;
}

/**
 *  @details    Sets the automata to be used when tokenizing
 *              the given input string. The automata passed
 *              should be dynamically allocated. If a previous
 *              automata had been set, it will be deleted.
 *
 *  @param[in]  automata        The automata to use.
 */
void Tokenizer::setAutomata(AbstractAutomata * automata)
{
    if (automata != 0) {
        if (automata_ != 0) {
            delete automata_;
        }
        automata_ = automata;
    }
}

/**
 *  @details    Sets the keyword set to be used when tokenizing
 *              the given input string. The keyword set passed
 *              should have been dynamically allocated. If a
 *              previous keyword set had been set, it will be
 *              deleted.
 *
 *  @param[in]  keywords        The keyword set to use.
 */
void Tokenizer::setKeywords(KeywordSet * keywords)
{
    if (keywords != 0) {
        if (keywords_ != 0) {
            delete keywords_;
        }
        keywords_ = keywords;
    }
}

/**
 *  @details    Sets the line reader to be used when this tokenizer
 *              consumes a line. The lineReader passed should have
 *              been dynamically allocated. If a previous line reader
 *              had been set, it will be deleted. Since the line reader
 *              is not strictly necessary for the Tokenizer to
 *              function properly, it can be set to a 0 value.
 *
 *  @param[in]  lineReader      The lineReader to use.
 */
void Tokenizer::setLineReader(LineFileReader * lineReader)
{
    if (lineReader_ != 0) {
        delete lineReader_;
    }
    lineReader_ = lineReader;
}

/**
 *  @details    Sets the error keeper to be used whenever an error is
 *              raised by this tokenizer. The errorKeeper passed should
 *              have been dynamically allocated. If a previous error keeper
 *              had been set, it will be deleted. Since the error keeper
 *              is not strictly necessary for the Tokenizer to
 *              function properly, it can be set to a 0 value.
 *
 *  @param[in]  errorKeeper     The errorKeeper to use.
 */
void Tokenizer::setErrorKeeper(ErrorKeeper * errorKeeper)
{
    if (errorKeeper_ != 0) {
        delete errorKeeper_;
    }
    errorKeeper_ = errorKeeper;
}

/**
 *  @details    Sets the line to use when tokenizing and also
 *              resets the index used when iterating over it.
 *
 *  @param[in]  line            The line to be tokenized.
 */
void Tokenizer::setLine(const string & line)
{
    line_ = line;
    charIdx = 0;
}

/**
 *  @details    Sets the line number on which the given tokens
 *              were found.
 *
 *  @param[in]  tokenLineNumber The line number.
 */
void Tokenizer::setTokenLineNumber(int tokenLineNumber)
{
    tokenLineNumber_ = tokenLineNumber;
}

/**
 *  @details    Gets the next token from the given input string.
 *              The token returned will be dynamically allocated,
 *              so one should remember to deallocate it later.
 *
 *  @return     The token found or 0 if no more tokens can be
 *              extracted.
 */
Token * Tokenizer::getToken()
{
    Token * token = 0;
    string symbol;
    int lastState;

    if (lineReader_ != 0) {
        while ((charIdx >= line_.length() || spaceOnlyLine()) && lineReader_->hasNext()) {
            lineReader_->sendNextLine(*this);
        }
    }

    if ((charIdx < line_.length()) && (automata_ != 0) && (keywords_ != 0)) {
        lastState = getTokenString(symbol);
        if (keywords_->isKeyword(symbol)) {
            token = new Token(keywords_->getKeywordId(symbol), tokenStartIndex,
                              tokenLineNumber_, symbol);
        } else if (automata_->isAcceptState(lastState)) {
            token = new Token(automata_->getTokenType(lastState), tokenStartIndex,
                              tokenLineNumber_, symbol);
        }
    }

    return token;
}

/**
 *  @details    Checks if an error has ocurred during the execution
 *              of the tokenizer.
 *
 *  @return     A boolean value indicating if an error has occur.
 */
bool Tokenizer::hasError() const
{
    bool errorExists = false;

    if (errorKeeper_ != 0) {
        errorExists = errorKeeper_->hasError();
    }

    return errorExists;
}

/////////////
// Private //
/////////////

/**
 *  @details    Algorithm used to build the substring of the
 *              input string to be included on the next token.
 *
 *  @param[out]  symbol          The string on which to copy the token's symbol.
 *
 *  @return     Returns the state at which the algorithm stopped. If
 *              an error ocurred, -1 is returned. If the algorithm
 *              stopped because the end of the string was reached
 *              before a full token was found, the last state is
 *              returned.
 */
int Tokenizer::getTokenString(string & symbol)
{
    int state = 0;
    unsigned lineLength = line_.length();
    bool done = false;
    bool error = false;
    bool gotFirstChar = false;

    while ((!done) && (!error) && (charIdx < lineLength)) {
        state = automata_->nextState(state, line_[charIdx]);
        if (state > 0) {
            if (!gotFirstChar) {
                gotFirstChar = true;
                tokenStartIndex = charIdx;
            }
            symbol.push_back(line_[charIdx]);
            if (automata_->isAcceptState(state)) {
                if (!automata_->includeNextChar(state, line_, charIdx)) {
                    done = true;
                }
            }
        } else if (state < 0) {
            error = true;
        }
        charIdx++;
    }

    if (error) {
        if (errorKeeper_ != 0) {
            errorKeeper_->addError(LEXIC_INPUT_ERROR, "Lexic Error: Wrong token formation | Unexpected symbol.");
        }
    } else if (!done) {
        if (errorKeeper_ != 0) {
            errorKeeper_->addError(TOKEN_NO_END_ERROR, "Lexic Error: Could not finish building last token.");
        }
    }

    return state;
}

/**
 *  @details    Checks if the line to be tokenized only has whitespaces.
 *
 *  @return     A boolean value indicating if a whitespace only line has
 *              been set or read.
 */
bool Tokenizer::spaceOnlyLine()
{
    int size = line_.size();
    bool spaceOnly = true;

    for (int i = 0; i < size && spaceOnly; i++) {
        if (!isspace(line_[i])) {
            spaceOnly = false;
        }
    }

    return spaceOnly;
}
<|endoftext|>


<commit_before>// condition.cxx - Declarations and inline methods for property conditions.
//
// Written by David Megginson, started 2000.
// CLO May 2003 - Split out condition specific code.
//
// This file is in the Public Domain, and comes with no warranty.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear/compiler.h>
#endif

// #include <iostream>

#include <simgear/structure/exception.hxx>

#include "props.hxx"
#include "condition.hxx"

using std::istream;
using std::ostream;

////////////////////////////////////////////////////////////////////////
// Implementation of SGCondition.
////////////////////////////////////////////////////////////////////////

SGCondition::SGCondition ()
{
}

SGCondition::~SGCondition ()
{
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGPropertyCondition.
////////////////////////////////////////////////////////////////////////

SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
                                           const char *propname )
    : _node( prop_root->getNode(propname, true) )
{
}

SGPropertyCondition::~SGPropertyCondition ()
{
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGNotCondition.
////////////////////////////////////////////////////////////////////////

SGNotCondition::SGNotCondition (SGCondition * condition)
  : _condition(condition)
{
}

SGNotCondition::~SGNotCondition ()
{
}

bool
SGNotCondition::test () const
{
  return !(_condition->test());
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGAndCondition.
////////////////////////////////////////////////////////////////////////

SGAndCondition::SGAndCondition ()
{
}

SGAndCondition::~SGAndCondition ()
{
}

bool
SGAndCondition::test () const
{
  int nConditions = _conditions.size();
  for (int i = 0; i < nConditions; i++) {
    if (!_conditions[i]->test())
      return false;
  }
  return true;
}

void
SGAndCondition::addCondition (SGCondition * condition)
{
  _conditions.push_back(condition);
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGOrCondition.
////////////////////////////////////////////////////////////////////////

SGOrCondition::SGOrCondition ()
{
}

SGOrCondition::~SGOrCondition ()
{
}

bool
SGOrCondition::test () const
{
  int nConditions = _conditions.size();
  for (int i = 0; i < nConditions; i++) {
    if (_conditions[i]->test())
      return true;
  }
  return false;
}

void
SGOrCondition::addCondition (SGCondition * condition)
{
  _conditions.push_back(condition);
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGComparisonCondition.
////////////////////////////////////////////////////////////////////////

static int
doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
{
  switch (left->getType()) {
  case SGPropertyNode::BOOL: {
    bool v1 = left->getBoolValue();
    bool v2 = right->getBoolValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::INT: {
    int v1 = left->getIntValue();
    int v2 = right->getIntValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::LONG: {
    long v1 = left->getLongValue();
    long v2 = right->getLongValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::FLOAT: {
    float v1 = left->getFloatValue();
    float v2 = right->getFloatValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::DOUBLE: {
    double v1 = left->getDoubleValue();
    double v2 = right->getDoubleValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::STRING:
  case SGPropertyNode::NONE:
  case SGPropertyNode::UNSPECIFIED: {
    string v1 = left->getStringValue();
    string v2 = right->getStringValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  }
  throw sg_exception("condition: unrecognized node type in comparison");
  return 0;
}

SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
  : _type(type),
    _reverse(reverse),
    _left_property(0),
    _right_property(0),
    _right_value(0)
{
}

SGComparisonCondition::~SGComparisonCondition ()
{
}

bool
SGComparisonCondition::test () const
{
				// Always fail if incompletely specified
  if (_left_property == 0 ||
      (_right_property == 0 && _right_value == 0))
    return false;

				// Get LESS_THAN, EQUALS, or GREATER_THAN
  int cmp =
    doComparison(_left_property,
		 (_right_property != 0 ? _right_property : _right_value));
  if (!_reverse)
    return (cmp == _type);
  else
    return (cmp != _type);
}

void
SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
                                        const char * propname )
{
  _left_property = prop_root->getNode(propname, true);
}

void
SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
                                         const char * propname )
{
  _right_value = 0;
  _right_property = prop_root->getNode(propname, true);
}

void
SGComparisonCondition::setRightValue (const SGPropertyNode *node)
{
  _right_property = 0;
  _right_value = new SGPropertyNode(*node);
}

////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////

                                // Forward declaration
static SGCondition * readCondition( SGPropertyNode *prop_root,
                                    const SGPropertyNode *node );

static SGCondition *
readPropertyCondition( SGPropertyNode *prop_root,
                       const SGPropertyNode *node )
{
  return new SGPropertyCondition( prop_root, node->getStringValue() );
}

static SGCondition *
readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      return new SGNotCondition(condition);
  }
  SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
  return 0;
}

static SGCondition *
readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  SGAndCondition * andCondition = new SGAndCondition;
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      andCondition->addCondition(condition);
  }
  return andCondition;
}

static SGCondition *
readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  SGOrCondition * orCondition = new SGOrCondition;
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      orCondition->addCondition(condition);
  }
  return orCondition;
}

static SGCondition *
readComparison( SGPropertyNode *prop_root,
                const SGPropertyNode *node,
                SGComparisonCondition::Type type,
		bool reverse)
{
  SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
  condition->setLeftProperty(prop_root, node->getStringValue("property[0]"));
  if (node->hasValue("property[1]"))
    condition->setRightProperty(prop_root, node->getStringValue("property[1]"));
  else if (node->hasValue("value"))
    condition->setRightValue(node->getChild("value", 0));
  else
    throw sg_exception("condition: comparison without property[1] or value");

  return condition;
}

static SGCondition *
readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  const string &name = node->getName();
  if (name == "property")
    return readPropertyCondition(prop_root, node);
  else if (name == "not")
    return readNotCondition(prop_root, node);
  else if (name == "and")
    return readAndConditions(prop_root, node);
  else if (name == "or")
    return readOrConditions(prop_root, node);
  else if (name == "less-than")
    return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
                          false);
  else if (name == "less-than-equals")
    return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
                          true);
  else if (name == "greater-than")
    return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
                          false);
  else if (name == "greater-than-equals")
    return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
                          true);
  else if (name == "equals")
    return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
                          false);
  else if (name == "not-equals")
    return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
  else
    return 0;
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGConditional.
////////////////////////////////////////////////////////////////////////

SGConditional::SGConditional ()
  : _condition (0)
{
}

SGConditional::~SGConditional ()
{
}

void
SGConditional::setCondition (SGCondition * condition)
{
  _condition = condition;
}

bool
SGConditional::test () const
{
  return ((_condition == 0) || _condition->test());
}

// The top-level is always an implicit 'and' group
SGCondition *
sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  return readAndConditions(prop_root, node);
}

// end of condition.cxx
<commit_msg>Fix a warning from GCC - 'ALIAS' was unhandled in the switch stmt.<commit_after>// condition.cxx - Declarations and inline methods for property conditions.
//
// Written by David Megginson, started 2000.
// CLO May 2003 - Split out condition specific code.
//
// This file is in the Public Domain, and comes with no warranty.
//
// $Id$

#ifdef HAVE_CONFIG_H
#  include <simgear/compiler.h>
#endif

// #include <iostream>

#include <simgear/structure/exception.hxx>

#include "props.hxx"
#include "condition.hxx"

using std::istream;
using std::ostream;

////////////////////////////////////////////////////////////////////////
// Implementation of SGCondition.
////////////////////////////////////////////////////////////////////////

SGCondition::SGCondition ()
{
}

SGCondition::~SGCondition ()
{
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGPropertyCondition.
////////////////////////////////////////////////////////////////////////

SGPropertyCondition::SGPropertyCondition ( SGPropertyNode *prop_root,
                                           const char *propname )
    : _node( prop_root->getNode(propname, true) )
{
}

SGPropertyCondition::~SGPropertyCondition ()
{
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGNotCondition.
////////////////////////////////////////////////////////////////////////

SGNotCondition::SGNotCondition (SGCondition * condition)
  : _condition(condition)
{
}

SGNotCondition::~SGNotCondition ()
{
}

bool
SGNotCondition::test () const
{
  return !(_condition->test());
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGAndCondition.
////////////////////////////////////////////////////////////////////////

SGAndCondition::SGAndCondition ()
{
}

SGAndCondition::~SGAndCondition ()
{
}

bool
SGAndCondition::test () const
{
  int nConditions = _conditions.size();
  for (int i = 0; i < nConditions; i++) {
    if (!_conditions[i]->test())
      return false;
  }
  return true;
}

void
SGAndCondition::addCondition (SGCondition * condition)
{
  _conditions.push_back(condition);
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGOrCondition.
////////////////////////////////////////////////////////////////////////

SGOrCondition::SGOrCondition ()
{
}

SGOrCondition::~SGOrCondition ()
{
}

bool
SGOrCondition::test () const
{
  int nConditions = _conditions.size();
  for (int i = 0; i < nConditions; i++) {
    if (_conditions[i]->test())
      return true;
  }
  return false;
}

void
SGOrCondition::addCondition (SGCondition * condition)
{
  _conditions.push_back(condition);
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGComparisonCondition.
////////////////////////////////////////////////////////////////////////

static int
doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
{
  switch (left->getType()) {
  case SGPropertyNode::BOOL: {
    bool v1 = left->getBoolValue();
    bool v2 = right->getBoolValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::INT: {
    int v1 = left->getIntValue();
    int v2 = right->getIntValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::LONG: {
    long v1 = left->getLongValue();
    long v2 = right->getLongValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::FLOAT: {
    float v1 = left->getFloatValue();
    float v2 = right->getFloatValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::DOUBLE: {
    double v1 = left->getDoubleValue();
    double v2 = right->getDoubleValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  case SGPropertyNode::STRING:
  case SGPropertyNode::NONE:
  case SGPropertyNode::UNSPECIFIED: {
    string v1 = left->getStringValue();
    string v2 = right->getStringValue();
    if (v1 < v2)
      return SGComparisonCondition::LESS_THAN;
    else if (v1 > v2)
      return SGComparisonCondition::GREATER_THAN;
    else
      return SGComparisonCondition::EQUALS;
    break;
  }
  default:
    throw sg_exception("condition: unrecognized node type in comparison");
  }

  return 0;
}

SGComparisonCondition::SGComparisonCondition (Type type, bool reverse)
  : _type(type),
    _reverse(reverse),
    _left_property(0),
    _right_property(0),
    _right_value(0)
{
}

SGComparisonCondition::~SGComparisonCondition ()
{
}

bool
SGComparisonCondition::test () const
{
				// Always fail if incompletely specified
  if (_left_property == 0 ||
      (_right_property == 0 && _right_value == 0))
    return false;

				// Get LESS_THAN, EQUALS, or GREATER_THAN
  int cmp =
    doComparison(_left_property,
		 (_right_property != 0 ? _right_property : _right_value));
  if (!_reverse)
    return (cmp == _type);
  else
    return (cmp != _type);
}

void
SGComparisonCondition::setLeftProperty( SGPropertyNode *prop_root,
                                        const char * propname )
{
  _left_property = prop_root->getNode(propname, true);
}

void
SGComparisonCondition::setRightProperty( SGPropertyNode *prop_root,
                                         const char * propname )
{
  _right_value = 0;
  _right_property = prop_root->getNode(propname, true);
}

void
SGComparisonCondition::setRightValue (const SGPropertyNode *node)
{
  _right_property = 0;
  _right_value = new SGPropertyNode(*node);
}

////////////////////////////////////////////////////////////////////////
// Read a condition and use it if necessary.
////////////////////////////////////////////////////////////////////////

                                // Forward declaration
static SGCondition * readCondition( SGPropertyNode *prop_root,
                                    const SGPropertyNode *node );

static SGCondition *
readPropertyCondition( SGPropertyNode *prop_root,
                       const SGPropertyNode *node )
{
  return new SGPropertyCondition( prop_root, node->getStringValue() );
}

static SGCondition *
readNotCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      return new SGNotCondition(condition);
  }
  SG_LOG(SG_COCKPIT, SG_ALERT, "empty 'not' condition");
  return 0;
}

static SGCondition *
readAndConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  SGAndCondition * andCondition = new SGAndCondition;
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      andCondition->addCondition(condition);
  }
  return andCondition;
}

static SGCondition *
readOrConditions( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  SGOrCondition * orCondition = new SGOrCondition;
  int nChildren = node->nChildren();
  for (int i = 0; i < nChildren; i++) {
    const SGPropertyNode * child = node->getChild(i);
    SGCondition * condition = readCondition(prop_root, child);
    if (condition != 0)
      orCondition->addCondition(condition);
  }
  return orCondition;
}

static SGCondition *
readComparison( SGPropertyNode *prop_root,
                const SGPropertyNode *node,
                SGComparisonCondition::Type type,
		bool reverse)
{
  SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
  condition->setLeftProperty(prop_root, node->getStringValue("property[0]"));
  if (node->hasValue("property[1]"))
    condition->setRightProperty(prop_root, node->getStringValue("property[1]"));
  else if (node->hasValue("value"))
    condition->setRightValue(node->getChild("value", 0));
  else
    throw sg_exception("condition: comparison without property[1] or value");

  return condition;
}

static SGCondition *
readCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  const string &name = node->getName();
  if (name == "property")
    return readPropertyCondition(prop_root, node);
  else if (name == "not")
    return readNotCondition(prop_root, node);
  else if (name == "and")
    return readAndConditions(prop_root, node);
  else if (name == "or")
    return readOrConditions(prop_root, node);
  else if (name == "less-than")
    return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
                          false);
  else if (name == "less-than-equals")
    return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
                          true);
  else if (name == "greater-than")
    return readComparison(prop_root, node, SGComparisonCondition::GREATER_THAN,
                          false);
  else if (name == "greater-than-equals")
    return readComparison(prop_root, node, SGComparisonCondition::LESS_THAN,
                          true);
  else if (name == "equals")
    return readComparison(prop_root, node, SGComparisonCondition::EQUALS,
                          false);
  else if (name == "not-equals")
    return readComparison(prop_root, node, SGComparisonCondition::EQUALS, true);
  else
    return 0;
}

////////////////////////////////////////////////////////////////////////
// Implementation of SGConditional.
////////////////////////////////////////////////////////////////////////

SGConditional::SGConditional ()
  : _condition (0)
{
}

SGConditional::~SGConditional ()
{
}

void
SGConditional::setCondition (SGCondition * condition)
{
  _condition = condition;
}

bool
SGConditional::test () const
{
  return ((_condition == 0) || _condition->test());
}

// The top-level is always an implicit 'and' group
SGCondition *
sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node )
{
  return readAndConditions(prop_root, node);
}

// end of condition.cxx
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*
    treeitem.cpp

    A container for items of data supplied by the simple tree model.
*/

#include "treeitem.h"

#include <QStringList>
#include <QMessageBox>

//! [0]
TreeItem::TreeItem(const QVector<QVariant> &data, TreeItem *parent, QObject *qparent, bool header_item)
	: QObject(qparent)
	, is_header_item(header_item)
	, forbidden_tag_name_characters(R"(^:\-\+\.\,!@#$%&*;~`"'<>\^\(\)\\/\|\?\[\]\{\})")
	, tag_name_validator(QRegularExpression("[^0-9" + forbidden_tag_name_characters + "][" + forbidden_tag_name_characters + "]*"))
{
	parentItem = parent;
    itemData = data;
}
//! [0]

//! [1]
TreeItem::~TreeItem()
{
    qDeleteAll(childItems);
}
//! [1]

//! [2]
TreeItem *TreeItem::child(int number)
{
    return childItems.value(number);
}
//! [2]

//! [3]
int TreeItem::childCount() const
{
    return childItems.count();
}
//! [3]

//! [4]
int TreeItem::childNumber() const
{
    if (parentItem)
        return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

    return 0;
}
//! [4]

//! [5]
int TreeItem::columnCount() const
{
    return itemData.count();
}
//! [5]

//! [6]
QVariant TreeItem::data(int column) const
{
    return itemData.value(column);
}
//! [6]

//! [7]
bool TreeItem::insertChildren(int position, int count, int columns)
{
    if (position < 0 || position > childItems.size())
        return false;
	if (childItems.size() == 0 && !is_header_item)
		this->setData(1, QVariant(""));

    for (int row = 0; row < count; ++row) {
        QVector<QVariant> data(columns);
        TreeItem *item = new TreeItem(data, this);
        childItems.insert(position, item);
    }

    return true;
}
//! [7]

//! [8]
bool TreeItem::insertColumns(int position, int columns)
{
    if (position < 0 || position > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.insert(position, QVariant());

    foreach (TreeItem *child, childItems)
        child->insertColumns(position, columns);

    return true;
}
//! [8]

//! [9]
TreeItem *TreeItem::parent()
{
    return parentItem;
}
//! [9]

//! [10]
bool TreeItem::removeChildren(int position, int count)
{
    if (position < 0 || position + count > childItems.size())
        return false;

    for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

    return true;
}
//! [10]

bool TreeItem::removeColumns(int position, int columns)
{
    if (position < 0 || position + columns > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.remove(position);

    foreach (TreeItem *child, childItems)
        child->removeColumns(position, columns);

    return true;
}

//! [11]
bool TreeItem::setData(int column, const QVariant &value)
{
    if (column < 0 || column >= itemData.size())
        return false;

	bool success = true;
	if (childCount() == 0 || column != 1)
	{
		if (column == 0)
		{
			int pos = 0;
			QValidator::State state = tag_name_validator.validate(value.toString(), pos);
			if (state == QValidator::Acceptable)
				itemData[column] = value;
			else
			{
				QMessageBox::information(nullptr, "XKMLGen", tr("Incorrect tag name."));
				success = false;
			}
		}
		else
		{
			itemData[column] = value;
		}
	}
	else
	{
		emit changeOfNodeValueAttempted(itemData[0]);
		success = false;
	}
	return success;
}
//! [11]
<commit_msg>Added whitespace to the list of forbidden tag name characters.<commit_after>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*
    treeitem.cpp

    A container for items of data supplied by the simple tree model.
*/

#include "treeitem.h"

#include <QStringList>
#include <QMessageBox>

//! [0]
TreeItem::TreeItem(const QVector<QVariant> &data, TreeItem *parent, QObject *qparent, bool header_item)
	: QObject(qparent)
	, is_header_item(header_item)
	, forbidden_tag_name_characters(R"(^:\-\+\.\,!@#$%&*;~`"'<>\^\(\)\\/\|\?\[\]\{\} )")
	, tag_name_validator(QRegularExpression("[^0-9" + forbidden_tag_name_characters + "][" + forbidden_tag_name_characters + "]*"))
{
	parentItem = parent;
    itemData = data;
}
//! [0]

//! [1]
TreeItem::~TreeItem()
{
    qDeleteAll(childItems);
}
//! [1]

//! [2]
TreeItem *TreeItem::child(int number)
{
    return childItems.value(number);
}
//! [2]

//! [3]
int TreeItem::childCount() const
{
    return childItems.count();
}
//! [3]

//! [4]
int TreeItem::childNumber() const
{
    if (parentItem)
        return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

    return 0;
}
//! [4]

//! [5]
int TreeItem::columnCount() const
{
    return itemData.count();
}
//! [5]

//! [6]
QVariant TreeItem::data(int column) const
{
    return itemData.value(column);
}
//! [6]

//! [7]
bool TreeItem::insertChildren(int position, int count, int columns)
{
    if (position < 0 || position > childItems.size())
        return false;
	if (childItems.size() == 0 && !is_header_item)
		this->setData(1, QVariant(""));

    for (int row = 0; row < count; ++row) {
        QVector<QVariant> data(columns);
        TreeItem *item = new TreeItem(data, this);
        childItems.insert(position, item);
    }

    return true;
}
//! [7]

//! [8]
bool TreeItem::insertColumns(int position, int columns)
{
    if (position < 0 || position > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.insert(position, QVariant());

    foreach (TreeItem *child, childItems)
        child->insertColumns(position, columns);

    return true;
}
//! [8]

//! [9]
TreeItem *TreeItem::parent()
{
    return parentItem;
}
//! [9]

//! [10]
bool TreeItem::removeChildren(int position, int count)
{
    if (position < 0 || position + count > childItems.size())
        return false;

    for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

    return true;
}
//! [10]

bool TreeItem::removeColumns(int position, int columns)
{
    if (position < 0 || position + columns > itemData.size())
        return false;

    for (int column = 0; column < columns; ++column)
        itemData.remove(position);

    foreach (TreeItem *child, childItems)
        child->removeColumns(position, columns);

    return true;
}

//! [11]
bool TreeItem::setData(int column, const QVariant &value)
{
    if (column < 0 || column >= itemData.size())
        return false;

	bool success = true;
	if (childCount() == 0 || column != 1)
	{
		if (column == 0)
		{
			int pos = 0;
			QValidator::State state = tag_name_validator.validate(value.toString(), pos);
			if (state == QValidator::Acceptable)
				itemData[column] = value;
			else
			{
				QMessageBox::information(nullptr, "XKMLGen", tr("Incorrect tag name."));
				success = false;
			}
		}
		else
		{
			itemData[column] = value;
		}
	}
	else
	{
		emit changeOfNodeValueAttempted(itemData[0]);
		success = false;
	}
	return success;
}
//! [11]
<|endoftext|>


<commit_before>//
// Copyright (c) 2017. See AUTHORS file.
//
// 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 <vector>
#include <thread>

#include "iostream"

#include "operation.h"
#include "image.h"
#include "types.h"
#include "utils.h"

namespace pixl {

    // ----------------------------------------------------------------------------
    void flip_vertically(Image* img, i32 startColumn, i32 endColumn) {
        const auto lineSizeInBytes = img->width * img->channels;
        for (i32 column = startColumn; column < endColumn; column++) {
            u8* start = img->data + (column * img->channels);
            u8* end = start + (img->height * lineSizeInBytes);

            while (start <= end) {
                aswap(start, end, img->channels);
                start += lineSizeInBytes;
                end -= lineSizeInBytes;
            }
        }
    }

    // ----------------------------------------------------------------------------
    void flip_horizontally(Image* img, i32 startLine, i32 endLine) {
        const auto lineSizeInBytes = img->width * img->channels;
        for (i32 line = startLine; line < endLine; line++) {
            u8* start = img->data + (line * lineSizeInBytes);
            u8* end = start + lineSizeInBytes - img->channels;

            while (start <= end) {
                aswap(start, end, img->channels);
                start += img->channels;
                end -= img->channels;
            }
        }
    }

    // ----------------------------------------------------------------------------
    void FlipTransformation::apply(Image* image) {
        // Run operation on main thread if numThreads <= 1
        if(numThreads <= 1) {
            if (this->orientation == Orientation::HORIZONTAL) {
                flip_horizontally(image, 0, image->height);
            } else if (this->orientation == Orientation::VERTICAL) {
                flip_vertically(image, 0, image->width);
            }
            return;
        }

        // create n threads
        std::vector<std::thread> threads;
        threads.reserve(this->numThreads);

        // start threads
        if (this->orientation == Orientation::HORIZONTAL) {
            auto chunk = image->height / numThreads;
            for (i32 i = 0; i < numThreads; i++) {
                threads.emplace_back(flip_horizontally, image, chunk * i, chunk * i + chunk);
            }
        } else if (this->orientation == Orientation::VERTICAL) {
            auto chunk = image->width / numThreads;
            for (i32 i = 0; i < numThreads; i++) {
                threads.emplace_back(flip_vertically, image, chunk * i, chunk * i + chunk);
            }
        }

        // wait until everybody is finished
        for (auto& t : threads) {
            t.join();
        }
    }
}<commit_msg>Fixed vertical flip<commit_after>//
// Copyright (c) 2017. See AUTHORS file.
//
// 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 <vector>
#include <thread>

#include "iostream"

#include "operation.h"
#include "image.h"
#include "types.h"
#include "utils.h"

namespace pixl {

    // ----------------------------------------------------------------------------
    void flip_vertically(Image* img, i32 startColumn, i32 endColumn) {
        const auto lineSizeInBytes = img->width * img->channels;
        const auto lastLine = (img->height-1) * lineSizeInBytes;
        for (i32 column = startColumn; column < endColumn; column++) {
            u8* start = img->data + (column * img->channels);
            u8* end = start + lastLine;

            while (start <= end) {
                aswap(start, end, img->channels);
                start += lineSizeInBytes;
                end -= lineSizeInBytes;
            }
        }
    }

    // ----------------------------------------------------------------------------
    void flip_horizontally(Image* img, i32 startLine, i32 endLine) {
        const auto lineSizeInBytes = img->width * img->channels;
        for (i32 line = startLine; line < endLine; line++) {
            u8* start = img->data + (line * lineSizeInBytes);
            u8* end = start + lineSizeInBytes - img->channels;

            while (start <= end) {
                aswap(start, end, img->channels);
                start += img->channels;
                end -= img->channels;
            }
        }
    }

    // ----------------------------------------------------------------------------
    void FlipTransformation::apply(Image* image) {
        // Run operation on main thread if numThreads <= 1
        if(numThreads <= 1) {
            if (this->orientation == Orientation::HORIZONTAL) {
                flip_horizontally(image, 0, image->height);
            } else if (this->orientation == Orientation::VERTICAL) {
                flip_vertically(image, 0, image->width);
            }
            return;
        }

        // create n threads
        std::vector<std::thread> threads;
        threads.reserve(this->numThreads);

        // start threads
        if (this->orientation == Orientation::HORIZONTAL) {
            auto chunk = image->height / numThreads;
            for (i32 i = 0; i < numThreads; i++) {
                threads.emplace_back(flip_horizontally, image, chunk * i, chunk * i + chunk);
            }
        } else if (this->orientation == Orientation::VERTICAL) {
            auto chunk = image->width / numThreads;
            for (i32 i = 0; i < numThreads; i++) {
                threads.emplace_back(flip_vertically, image, chunk * i, chunk * i + chunk);
            }
        }

        // wait until everybody is finished
        for (auto& t : threads) {
            t.join();
        }
    }
}<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 1998-2010 by authors (see AUTHORS.txt )                 *
 *                                                                         *
 *   This file is part of LuxRays.                                         *
 *                                                                         *
 *   LuxRays 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.                                   *
 *                                                                         *
 *   LuxRays 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/>. *
 *                                                                         *
 *   LuxRays website: http://www.luxrender.net                             *
 ***************************************************************************/

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

#include "luxrays/core/pixel/samplebuffer.h"

#include "smalllux.h"
#include "sppm.h"
#include "renderconfig.h"
#include "displayfunc.h"
#include "hitpoints.h"

//------------------------------------------------------------------------------
// SPPMRenderThread
//------------------------------------------------------------------------------

SPPMRenderThread::SPPMRenderThread(unsigned int index, SPPMRenderEngine *re) {
	threadIndex = index;
	renderEngine = re;
	started = false;
}

SPPMRenderThread::~SPPMRenderThread() {
}

//------------------------------------------------------------------------------
// SPPMDeviceRenderThread
//------------------------------------------------------------------------------

SPPMDeviceRenderThread::SPPMDeviceRenderThread(const unsigned int index, const unsigned long seedBase,
		IntersectionDevice *device,	SPPMRenderEngine *re) : SPPMRenderThread(index, re) {
	intersectionDevice = device;
	reportedPermissionError = false;

	renderThread = NULL;

	rayBuffer = intersectionDevice->NewRayBuffer();
	if (threadIndex == 0)
		rayBufferHitPoints = intersectionDevice->NewRayBuffer();
	else
		rayBufferHitPoints = NULL;
}

SPPMDeviceRenderThread::~SPPMDeviceRenderThread() {
	if (started)
		Stop();

	delete rayBuffer;
	delete rayBufferHitPoints;
}

void SPPMDeviceRenderThread::Start() {
	SPPMRenderThread::Start();

	rayBuffer->Reset();
	if (threadIndex == 0)
		rayBufferHitPoints->Reset();

	// Create the thread for the rendering
	renderThread = new boost::thread(boost::bind(SPPMDeviceRenderThread::RenderThreadImpl, this));

	// Set renderThread priority
	bool res = SetThreadRRPriority(renderThread);
	if (res && !reportedPermissionError) {
		cerr << "[SPPMDeviceRenderThread::" << threadIndex << "] Failed to set ray intersection thread priority (you probably need root/administrator permission to set thread realtime priority)" << endl;
		reportedPermissionError = true;
	}
}

void SPPMDeviceRenderThread::Interrupt() {
	if (renderThread)
		renderThread->interrupt();
}

void SPPMDeviceRenderThread::Stop() {
	if (renderThread) {
		renderThread->interrupt();
		renderThread->join();
		delete renderThread;
		renderThread = NULL;
	}

	SPPMRenderThread::Stop();
}

void SPPMDeviceRenderThread::UpdateFilm(Film *film, HitPoints *hitPoints, SampleBuffer *sampleBuffer) {
	film->Reset();

	const unsigned int imgWidth = film->GetWidth();
	for (unsigned int i = 0; i < hitPoints->GetSize(); ++i) {
		HitPoint *hp = hitPoints->GetHitPoint(i);
		const float scrX = i % imgWidth;
		const float scrY = i / imgWidth;
		sampleBuffer->SplatSample(scrX, scrY, hp->radiance);

		if (sampleBuffer->IsFull()) {
			// Splat all samples on the film
			film->SplatSampleBuffer(true, sampleBuffer);
			sampleBuffer = film->GetFreeSampleBuffer();
		}
	}

	if (sampleBuffer->GetSampleCount() > 0) {
		// Splat all samples on the film
		film->SplatSampleBuffer(true, sampleBuffer);
		sampleBuffer = film->GetFreeSampleBuffer();
	}
}

void SPPMDeviceRenderThread::InitPhotonPath(Scene *scene, RandomGenerator *rndGen,
	PhotonPath *photonPath, Ray *ray, unsigned int *photonTracedPass) {
	// Select one light source
	float lpdf;
	const LightSource *light = scene->SampleAllLights(rndGen->floatValue(), &lpdf);

	// Initialize the photon path
	float pdf;
	photonPath->flux = light->Sample_L(scene,
		rndGen->floatValue(), rndGen->floatValue(),
		rndGen->floatValue(), rndGen->floatValue(),
		&pdf, ray);
	photonPath->flux /= pdf * lpdf;
	photonPath->depth = 0;

	AtomicInc(photonTracedPass);
}

void SPPMDeviceRenderThread::RenderThreadImpl(SPPMDeviceRenderThread *renderThread) {
	cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread started" << endl;

	SPPMRenderEngine *renderEngine = renderThread->renderEngine;
	Scene *scene = renderEngine->scene;
	RandomGenerator *rndGen = new RandomGenerator();
	rndGen->init(renderThread->threadIndex + renderEngine->seedBase + 1);

	IntersectionDevice *device = renderThread->intersectionDevice;
	RayBuffer *rayBuffer = renderThread->rayBuffer;
	RayBuffer *rayBufferHitPoints = renderThread->rayBufferHitPoints;

	if (renderThread->threadIndex == 0) {
		// Build the EyePaths list
		renderEngine->hitPoints = new HitPoints(
				scene, rndGen, device,
				rayBufferHitPoints, renderEngine->photonAlpha,
				renderEngine->maxEyePathDepth,
				renderEngine->film->GetWidth(), renderEngine->film->GetHeight(),
				renderEngine->accelType);
	}

	HitPoints *hitPoints = NULL;
	try {
		// Wait for other threads
		renderEngine->barrierStart->wait();

		hitPoints = renderEngine->hitPoints;

		//std::cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Tracing photon paths" << std::endl;

		// Generate photons from light sources
		std::vector<PhotonPath> photonPaths(rayBuffer->GetSize());
		Ray *rays = rayBuffer->GetRayBuffer();
		for (unsigned int i = 0; i < photonPaths.size(); ++i) {
			// Note: there is some assumption here about how the
			// rayBuffer->ReserveRay() work
			InitPhotonPath(scene, rndGen, &photonPaths[i], &rays[rayBuffer->ReserveRay()],
					&renderEngine->photonTracedPass);
		}

		while (!boost::this_thread::interruption_requested()) {
			// Trace the rays
			device->PushRayBuffer(rayBuffer);
			rayBuffer = device->PopRayBuffer();

			for (unsigned int i = 0; i < rayBuffer->GetRayCount(); ++i) {
				PhotonPath *photonPath = &photonPaths[i];
				Ray *ray = &rayBuffer->GetRayBuffer()[i];
				const RayHit *rayHit = &rayBuffer->GetHitBuffer()[i];

				if (rayHit->Miss()) {
					// Re-initialize the photon path
					InitPhotonPath(scene, rndGen, photonPath, ray,
							&renderEngine->photonTracedPass);
				} else {
					// Something was hit
					Point hitPoint;
					Spectrum surfaceColor;
					Normal N, shadeN;
					if (GetHitPointInformation(scene, rndGen, ray, rayHit, hitPoint,
							surfaceColor, N, shadeN))
						continue;

					// Get the material
					const unsigned int currentTriangleIndex = rayHit->index;
					const Material *triMat = scene->triangleMaterials[currentTriangleIndex];

					if (triMat->IsLightSource()) {
						// Re-initialize the photon path
						InitPhotonPath(scene, rndGen, photonPath, ray,
								&renderEngine->photonTracedPass);
					} else {
						const SurfaceMaterial *triSurfMat = (SurfaceMaterial *)triMat;

						float fPdf;
						Vector wi;
						bool specularBounce;
						const Spectrum f = triSurfMat->Sample_f(-ray->d, &wi, N, shadeN,
								rndGen->floatValue(), rndGen->floatValue(), rndGen->floatValue(),
								false, &fPdf, specularBounce) * surfaceColor;

						if (!specularBounce)
							hitPoints->AddFlux(hitPoint, shadeN, -ray->d, photonPath->flux);

						// Check if we reached the max. depth
						if (photonPath->depth < renderEngine->maxPhotonPathDepth) {
							// Build the next vertex path ray
							if ((fPdf <= 0.f) || f.Black()) {
								// Re-initialize the photon path
								InitPhotonPath(scene, rndGen, photonPath, ray,
										&renderEngine->photonTracedPass);
							} else {
								photonPath->depth++;
								photonPath->flux *= f / fPdf;

								// Russian Roulette
								const float p = 0.7f;
								if ((photonPath->depth < 2) || (specularBounce)) {
									*ray = Ray(hitPoint, wi);
								} else if (rndGen->floatValue() < p) {
									photonPath->flux /= p;
									*ray = Ray(hitPoint, wi);
								} else {
									// Re-initialize the photon path
									InitPhotonPath(scene, rndGen, photonPath, ray,
											&renderEngine->photonTracedPass);
								}
							}
						} else {
							// Re-initialize the photon path
							InitPhotonPath(scene, rndGen, photonPath, ray,
									&renderEngine->photonTracedPass);
						}
					}
				}
			}

			// Check if it is time to do an eye pass
			// TODO: add a parameter to tune rehashing intervals
			if (renderEngine->photonTracedPass > renderEngine->stochasticInterval) {
				// Wait for other threads
				renderEngine->barrierStop->wait();

				// The first thread does the eye pass
				if (renderThread->threadIndex == 0) {
					const long long count = renderEngine->photonTracedTotal + renderEngine->photonTracedPass;
					hitPoints->Recast(rndGen, rayBufferHitPoints, count);

					// Update the frame buffer
					UpdateFilm(renderEngine->film, hitPoints, renderEngine->sampleBuffer);

					renderEngine->photonTracedTotal = count;
					renderEngine->photonTracedPass = 0;
				}

				// Wait for other threads
				renderEngine->barrierStart->wait();
				//std::cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Tracing photon paths" << std::endl;
			}
		}

		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread halted" << endl;
	} catch (boost::thread_interrupted) {
		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread halted" << endl;
	}
#if !defined(LUXRAYS_DISABLE_OPENCL)
	catch (cl::Error err) {
		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread ERROR: " << err.what() << "(" << err.err() << ")" << endl;
	}
#endif

	// Wait for other threads
	renderEngine->barrierExit->wait();

	if (renderThread->threadIndex == 0) {
		renderEngine->hitPoints = NULL;
		delete hitPoints;
	}
}

//------------------------------------------------------------------------------
// SPPMRenderEngine
//------------------------------------------------------------------------------

SPPMRenderEngine::SPPMRenderEngine(SLGScene *scn, Film *flm,
		vector<IntersectionDevice *> intersectionDev,
		const Properties &cfg) : RenderEngine(scn, flm) {
	intersectionDevices = intersectionDev;

	accelType = HASH_GRID;
	seedBase = (unsigned long)(WallClockTime() / 1000.0);
	photonAlpha = 0.7f;
	maxEyePathDepth = 16;
	maxPhotonPathDepth = 8;
	stochasticInterval = cfg.GetInt("sppm.stochastic.count", 10000000);

	sampleBuffer = film->GetFreeSampleBuffer();

	// Create and start render threads
	const size_t renderThreadCount = intersectionDevices.size();
	cerr << "Starting "<< renderThreadCount << " SPPM render threads" << endl;
	for (size_t i = 0; i < renderThreadCount; ++i) {
		SPPMDeviceRenderThread *t = new SPPMDeviceRenderThread(i, seedBase, intersectionDevices[i], this);
		renderThreads.push_back(t);
	}
}

SPPMRenderEngine::~SPPMRenderEngine() {
	if (started) {
		Interrupt();
		Stop();
	}

	for (size_t i = 0; i < renderThreads.size(); ++i)
		delete renderThreads[i];

	film->FreeSampleBuffer(sampleBuffer);
}

void SPPMRenderEngine::Start() {
	RenderEngine::Start();

	photonTracedTotal = 0;
	photonTracedPass = 0;

	// Create synchronization barriers
	barrierStop = new boost::barrier(renderThreads.size());
	barrierStart = new boost::barrier(renderThreads.size());
	barrierExit = new boost::barrier(renderThreads.size());

	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Start();
}

void SPPMRenderEngine::Interrupt() {
	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Interrupt();
}

void SPPMRenderEngine::Stop() {
	RenderEngine::Stop();

	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Stop();

	delete barrierStop;
	delete barrierStart;
	delete barrierExit;
}

void SPPMRenderEngine::Reset() {
	assert (!started);
}

unsigned int SPPMRenderEngine::GetPass() const {
	return (hitPoints) ? hitPoints->GetPassCount() : 0;
}

unsigned int SPPMRenderEngine::GetThreadCount() const {
	return renderThreads.size();
}
<commit_msg>SLG: fixed an SPPM unitialized variable<commit_after>/***************************************************************************
 *   Copyright (C) 1998-2010 by authors (see AUTHORS.txt )                 *
 *                                                                         *
 *   This file is part of LuxRays.                                         *
 *                                                                         *
 *   LuxRays 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.                                   *
 *                                                                         *
 *   LuxRays 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/>. *
 *                                                                         *
 *   LuxRays website: http://www.luxrender.net                             *
 ***************************************************************************/

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

#include "luxrays/core/pixel/samplebuffer.h"

#include "smalllux.h"
#include "sppm.h"
#include "renderconfig.h"
#include "displayfunc.h"
#include "hitpoints.h"

//------------------------------------------------------------------------------
// SPPMRenderThread
//------------------------------------------------------------------------------

SPPMRenderThread::SPPMRenderThread(unsigned int index, SPPMRenderEngine *re) {
	threadIndex = index;
	renderEngine = re;
	started = false;
}

SPPMRenderThread::~SPPMRenderThread() {
}

//------------------------------------------------------------------------------
// SPPMDeviceRenderThread
//------------------------------------------------------------------------------

SPPMDeviceRenderThread::SPPMDeviceRenderThread(const unsigned int index, const unsigned long seedBase,
		IntersectionDevice *device,	SPPMRenderEngine *re) : SPPMRenderThread(index, re) {
	intersectionDevice = device;
	reportedPermissionError = false;

	renderThread = NULL;

	rayBuffer = intersectionDevice->NewRayBuffer();
	if (threadIndex == 0)
		rayBufferHitPoints = intersectionDevice->NewRayBuffer();
	else
		rayBufferHitPoints = NULL;
}

SPPMDeviceRenderThread::~SPPMDeviceRenderThread() {
	if (started)
		Stop();

	delete rayBuffer;
	delete rayBufferHitPoints;
}

void SPPMDeviceRenderThread::Start() {
	SPPMRenderThread::Start();

	rayBuffer->Reset();
	if (threadIndex == 0)
		rayBufferHitPoints->Reset();

	// Create the thread for the rendering
	renderThread = new boost::thread(boost::bind(SPPMDeviceRenderThread::RenderThreadImpl, this));

	// Set renderThread priority
	bool res = SetThreadRRPriority(renderThread);
	if (res && !reportedPermissionError) {
		cerr << "[SPPMDeviceRenderThread::" << threadIndex << "] Failed to set ray intersection thread priority (you probably need root/administrator permission to set thread realtime priority)" << endl;
		reportedPermissionError = true;
	}
}

void SPPMDeviceRenderThread::Interrupt() {
	if (renderThread)
		renderThread->interrupt();
}

void SPPMDeviceRenderThread::Stop() {
	if (renderThread) {
		renderThread->interrupt();
		renderThread->join();
		delete renderThread;
		renderThread = NULL;
	}

	SPPMRenderThread::Stop();
}

void SPPMDeviceRenderThread::UpdateFilm(Film *film, HitPoints *hitPoints, SampleBuffer *sampleBuffer) {
	film->Reset();

	const unsigned int imgWidth = film->GetWidth();
	for (unsigned int i = 0; i < hitPoints->GetSize(); ++i) {
		HitPoint *hp = hitPoints->GetHitPoint(i);
		const float scrX = i % imgWidth;
		const float scrY = i / imgWidth;
		sampleBuffer->SplatSample(scrX, scrY, hp->radiance);

		if (sampleBuffer->IsFull()) {
			// Splat all samples on the film
			film->SplatSampleBuffer(true, sampleBuffer);
			sampleBuffer = film->GetFreeSampleBuffer();
		}
	}

	if (sampleBuffer->GetSampleCount() > 0) {
		// Splat all samples on the film
		film->SplatSampleBuffer(true, sampleBuffer);
		sampleBuffer = film->GetFreeSampleBuffer();
	}
}

void SPPMDeviceRenderThread::InitPhotonPath(Scene *scene, RandomGenerator *rndGen,
	PhotonPath *photonPath, Ray *ray, unsigned int *photonTracedPass) {
	// Select one light source
	float lpdf;
	const LightSource *light = scene->SampleAllLights(rndGen->floatValue(), &lpdf);

	// Initialize the photon path
	float pdf;
	photonPath->flux = light->Sample_L(scene,
		rndGen->floatValue(), rndGen->floatValue(),
		rndGen->floatValue(), rndGen->floatValue(),
		&pdf, ray);
	photonPath->flux /= pdf * lpdf;
	photonPath->depth = 0;

	AtomicInc(photonTracedPass);
}

void SPPMDeviceRenderThread::RenderThreadImpl(SPPMDeviceRenderThread *renderThread) {
	cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread started" << endl;

	SPPMRenderEngine *renderEngine = renderThread->renderEngine;
	Scene *scene = renderEngine->scene;
	RandomGenerator *rndGen = new RandomGenerator();
	rndGen->init(renderThread->threadIndex + renderEngine->seedBase + 1);

	IntersectionDevice *device = renderThread->intersectionDevice;
	RayBuffer *rayBuffer = renderThread->rayBuffer;
	RayBuffer *rayBufferHitPoints = renderThread->rayBufferHitPoints;

	if (renderThread->threadIndex == 0) {
		// Build the EyePaths list
		renderEngine->hitPoints = new HitPoints(
				scene, rndGen, device,
				rayBufferHitPoints, renderEngine->photonAlpha,
				renderEngine->maxEyePathDepth,
				renderEngine->film->GetWidth(), renderEngine->film->GetHeight(),
				renderEngine->accelType);
	}

	HitPoints *hitPoints = NULL;
	try {
		// Wait for other threads
		renderEngine->barrierStart->wait();

		hitPoints = renderEngine->hitPoints;

		//std::cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Tracing photon paths" << std::endl;

		// Generate photons from light sources
		std::vector<PhotonPath> photonPaths(rayBuffer->GetSize());
		Ray *rays = rayBuffer->GetRayBuffer();
		for (unsigned int i = 0; i < photonPaths.size(); ++i) {
			// Note: there is some assumption here about how the
			// rayBuffer->ReserveRay() work
			InitPhotonPath(scene, rndGen, &photonPaths[i], &rays[rayBuffer->ReserveRay()],
					&renderEngine->photonTracedPass);
		}

		while (!boost::this_thread::interruption_requested()) {
			// Trace the rays
			device->PushRayBuffer(rayBuffer);
			rayBuffer = device->PopRayBuffer();

			for (unsigned int i = 0; i < rayBuffer->GetRayCount(); ++i) {
				PhotonPath *photonPath = &photonPaths[i];
				Ray *ray = &rayBuffer->GetRayBuffer()[i];
				const RayHit *rayHit = &rayBuffer->GetHitBuffer()[i];

				if (rayHit->Miss()) {
					// Re-initialize the photon path
					InitPhotonPath(scene, rndGen, photonPath, ray,
							&renderEngine->photonTracedPass);
				} else {
					// Something was hit
					Point hitPoint;
					Spectrum surfaceColor;
					Normal N, shadeN;
					if (GetHitPointInformation(scene, rndGen, ray, rayHit, hitPoint,
							surfaceColor, N, shadeN))
						continue;

					// Get the material
					const unsigned int currentTriangleIndex = rayHit->index;
					const Material *triMat = scene->triangleMaterials[currentTriangleIndex];

					if (triMat->IsLightSource()) {
						// Re-initialize the photon path
						InitPhotonPath(scene, rndGen, photonPath, ray,
								&renderEngine->photonTracedPass);
					} else {
						const SurfaceMaterial *triSurfMat = (SurfaceMaterial *)triMat;

						float fPdf;
						Vector wi;
						bool specularBounce;
						const Spectrum f = triSurfMat->Sample_f(-ray->d, &wi, N, shadeN,
								rndGen->floatValue(), rndGen->floatValue(), rndGen->floatValue(),
								false, &fPdf, specularBounce) * surfaceColor;

						if (!specularBounce)
							hitPoints->AddFlux(hitPoint, shadeN, -ray->d, photonPath->flux);

						// Check if we reached the max. depth
						if (photonPath->depth < renderEngine->maxPhotonPathDepth) {
							// Build the next vertex path ray
							if ((fPdf <= 0.f) || f.Black()) {
								// Re-initialize the photon path
								InitPhotonPath(scene, rndGen, photonPath, ray,
										&renderEngine->photonTracedPass);
							} else {
								photonPath->depth++;
								photonPath->flux *= f / fPdf;

								// Russian Roulette
								const float p = 0.7f;
								if ((photonPath->depth < 2) || (specularBounce)) {
									*ray = Ray(hitPoint, wi);
								} else if (rndGen->floatValue() < p) {
									photonPath->flux /= p;
									*ray = Ray(hitPoint, wi);
								} else {
									// Re-initialize the photon path
									InitPhotonPath(scene, rndGen, photonPath, ray,
											&renderEngine->photonTracedPass);
								}
							}
						} else {
							// Re-initialize the photon path
							InitPhotonPath(scene, rndGen, photonPath, ray,
									&renderEngine->photonTracedPass);
						}
					}
				}
			}

			// Check if it is time to do an eye pass
			// TODO: add a parameter to tune rehashing intervals
			if (renderEngine->photonTracedPass > renderEngine->stochasticInterval) {
				// Wait for other threads
				renderEngine->barrierStop->wait();

				// The first thread does the eye pass
				if (renderThread->threadIndex == 0) {
					const long long count = renderEngine->photonTracedTotal + renderEngine->photonTracedPass;
					hitPoints->Recast(rndGen, rayBufferHitPoints, count);

					// Update the frame buffer
					UpdateFilm(renderEngine->film, hitPoints, renderEngine->sampleBuffer);

					renderEngine->photonTracedTotal = count;
					renderEngine->photonTracedPass = 0;
				}

				// Wait for other threads
				renderEngine->barrierStart->wait();
				//std::cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Tracing photon paths" << std::endl;
			}
		}

		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread halted" << endl;
	} catch (boost::thread_interrupted) {
		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread halted" << endl;
	}
#if !defined(LUXRAYS_DISABLE_OPENCL)
	catch (cl::Error err) {
		cerr << "[SPPMDeviceRenderThread::" << renderThread->threadIndex << "] Rendering thread ERROR: " << err.what() << "(" << err.err() << ")" << endl;
	}
#endif

	// Wait for other threads
	renderEngine->barrierExit->wait();

	if (renderThread->threadIndex == 0) {
		renderEngine->hitPoints = NULL;
		delete hitPoints;
	}
}

//------------------------------------------------------------------------------
// SPPMRenderEngine
//------------------------------------------------------------------------------

SPPMRenderEngine::SPPMRenderEngine(SLGScene *scn, Film *flm,
		vector<IntersectionDevice *> intersectionDev,
		const Properties &cfg) : RenderEngine(scn, flm) {
	intersectionDevices = intersectionDev;

	accelType = HASH_GRID;
	seedBase = (unsigned long)(WallClockTime() / 1000.0);
	photonAlpha = 0.7f;
	maxEyePathDepth = 16;
	maxPhotonPathDepth = 8;
	stochasticInterval = cfg.GetInt("sppm.stochastic.count", 10000000);

	hitPoints = NULL;
	sampleBuffer = film->GetFreeSampleBuffer();

	// Create and start render threads
	const size_t renderThreadCount = intersectionDevices.size();
	cerr << "Starting "<< renderThreadCount << " SPPM render threads" << endl;
	for (size_t i = 0; i < renderThreadCount; ++i) {
		SPPMDeviceRenderThread *t = new SPPMDeviceRenderThread(i, seedBase, intersectionDevices[i], this);
		renderThreads.push_back(t);
	}
}

SPPMRenderEngine::~SPPMRenderEngine() {
	if (started) {
		Interrupt();
		Stop();
	}

	for (size_t i = 0; i < renderThreads.size(); ++i)
		delete renderThreads[i];

	film->FreeSampleBuffer(sampleBuffer);
}

void SPPMRenderEngine::Start() {
	RenderEngine::Start();

	photonTracedTotal = 0;
	photonTracedPass = 0;

	// Create synchronization barriers
	barrierStop = new boost::barrier(renderThreads.size());
	barrierStart = new boost::barrier(renderThreads.size());
	barrierExit = new boost::barrier(renderThreads.size());

	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Start();
}

void SPPMRenderEngine::Interrupt() {
	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Interrupt();
}

void SPPMRenderEngine::Stop() {
	RenderEngine::Stop();

	for (size_t i = 0; i < renderThreads.size(); ++i)
		renderThreads[i]->Stop();

	delete barrierStop;
	delete barrierStart;
	delete barrierExit;
}

void SPPMRenderEngine::Reset() {
	assert (!started);
}

unsigned int SPPMRenderEngine::GetPass() const {
	return (hitPoints) ? hitPoints->GetPassCount() : 0;
}

unsigned int SPPMRenderEngine::GetThreadCount() const {
	return renderThreads.size();
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_mem_startclocks.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_mem_startclocks.C
///
/// @brief Start clocks on MBA/MCAs
//------------------------------------------------------------------------------
// *HWP HW Owner        : Anusha Reddy Rangareddygari <anusrang@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Sunil Kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 1
// *HWP Consumed by     : HB
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_mem_startclocks.H"

fapi2::ReturnCode p9_mem_startclocks(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chiplet)
{
    FAPI_DBG("Entering ...");

    FAPI_DBG("Exiting ...");

    return fapi2::FAPI2_RC_SUCCESS;

}
<commit_msg>Level 2 HWP p9_mem_startclocks<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_mem_startclocks.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_mem_startclocks.C
///
/// @brief Start clocks on MBA/MCAs
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Sunil kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 2
// *HWP Consumed by     : HB
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_mem_startclocks.H"
#include "p9_const_common.H"
#include "p9_misc_scom_addresses_fld.H"
#include "p9_perv_scom_addresses.H"
#include "p9_perv_scom_addresses_fld.H"
#include "p9_quad_scom_addresses_fld.H"
#include "p9_sbe_common.H"

enum P9_MEM_STARTCLOCKS_Private_Constants
{
    CLOCK_CMD = 0x1,
    STARTSLAVE = 0x1,
    STARTMASTER = 0x1,
    REGIONS_ALL_EXCEPT_VITAL_NESTPLL = 0x7FE,
    CLOCK_TYPES = 0x7,
    DONT_STARTMASTER = 0x0,
    DONT_STARTSLAVE = 0x0
};

static fapi2::ReturnCode p9_mem_startclocks_check_checkstop_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet);

static fapi2::ReturnCode p9_mem_startclocks_cplt_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet);

static fapi2::ReturnCode p9_mem_startclocks_flushmode(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet);

fapi2::ReturnCode p9_mem_startclocks(const
                                     fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip)
{
    FAPI_DBG("Entering ...");

    FAPI_INF("Switch MC meshs to Nest mesh");

    for (auto l_trgt_chplt : i_target_chip.getChildren<fapi2::TARGET_TYPE_PERV>
         (fapi2::TARGET_FILTER_ALL_MC, fapi2::TARGET_STATE_FUNCTIONAL))
    {

        FAPI_INF("Call p9_mem_startclocks_cplt_ctrl_action_function for Mc chiplets");
        FAPI_TRY(p9_mem_startclocks_cplt_ctrl_action_function(l_trgt_chplt));

        FAPI_INF("Call module align chiplets for Mc chiplets");
        FAPI_TRY(p9_sbe_common_align_chiplets(l_trgt_chplt));

        FAPI_INF("Call module clock start stop for MC01, MC23.");
        FAPI_TRY(p9_sbe_common_clock_start_stop(l_trgt_chplt, CLOCK_CMD,
                                                DONT_STARTSLAVE, DONT_STARTMASTER, REGIONS_ALL_EXCEPT_VITAL_NESTPLL,
                                                CLOCK_TYPES));

        FAPI_INF("Call p9_mem_startclocks_check_checkstop_function for Mc chiplets ");
        FAPI_TRY(p9_mem_startclocks_check_checkstop_function(l_trgt_chplt));

        FAPI_INF("Call p9_mem_startclocks_flushmode for Mc chiplets");
        FAPI_TRY(p9_mem_startclocks_flushmode(l_trgt_chplt));

    }

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}

/// @brief --drop chiplet fence
/// --check checkstop register
/// --clear flush inhibit to go into flush mode
///
/// @param[in]     i_target_chiplet   Reference to TARGET_TYPE_PERV target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode p9_mem_startclocks_check_checkstop_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet)
{
    fapi2::buffer<uint64_t> l_read_reg;
    fapi2::buffer<uint64_t> l_data64;
    FAPI_DBG("Entering ...");

    FAPI_INF("Drop chiplet fence");
    //Setting NET_CTRL0 register value
    l_data64.flush<1>();
    l_data64.clearBit<PEC_STACK0_NET_CTRL0_FENCE_EN>();  //NET_CTRL0.FENCE_EN = 0
    FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_NET_CTRL0_WAND, l_data64));

    FAPI_INF("Check checkstop register");
    //Getting XFIR register value
    FAPI_TRY(fapi2::getScom(i_target_chiplet, PERV_XFIR,
                            l_read_reg)); //l_read_reg = XFIR

    FAPI_ASSERT(l_read_reg == 0,
                fapi2::READ_ALL_CHECKSTOP_ERR()
                .set_READ_ALL_CHECKSTOP(l_read_reg),
                "ERROR: COMBINE ALL CHECKSTOP ERROR");

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}

/// @brief --drop vital fence
/// --reset abstclk muxsel and syncclk muxsel
///
/// @param[in]     i_target_chiplet   Reference to TARGET_TYPE_PERV target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode p9_mem_startclocks_cplt_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet)
{
    fapi2::buffer<uint64_t> l_data64;
    FAPI_DBG("Entering ...");

    // Local variable and constant definition
    fapi2::buffer <uint32_t> l_attr_pg;

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PG, i_target_chiplet, l_attr_pg));

    l_attr_pg.invert();

    FAPI_INF("Drop partial good fences");
    //Setting CPLT_CTRL1 register value
    l_data64.flush<0>();
    //CPLT_CTRL1.TC_VITL_REGION_FENCE = l_attr_pg.getBit<19>()
    l_data64.writeBit<PEC_CPLT_CTRL1_TC_VITL_REGION_FENCE>(l_attr_pg.getBit<19>());
    //CPLT_CTRL1.TC_PERV_REGION_FENCE = l_attr_pg.getBit<20>()
    l_data64.writeBit<PEC_CPLT_CTRL1_TC_PERV_REGION_FENCE>(l_attr_pg.getBit<20>());
    //CPLT_CTRL1.TC_REGION1_FENCE = l_attr_pg.getBit<21>()
    l_data64.writeBit<PEC_CPLT_CTRL1_TC_REGION1_FENCE>(l_attr_pg.getBit<21>());
    //CPLT_CTRL1.TC_REGION2_FENCE = l_attr_pg.getBit<22>()
    l_data64.writeBit<PEC_CPLT_CTRL1_TC_REGION2_FENCE>(l_attr_pg.getBit<22>());
    //CPLT_CTRL1.TC_REGION3_FENCE = l_attr_pg.getBit<23>()
    l_data64.writeBit<PERV_1_CPLT_CTRL1_TC_REGION3_FENCE>(l_attr_pg.getBit<23>());
    //CPLT_CTRL1.TC_REGION4_FENCE = l_attr_pg.getBit<24>()
    l_data64.writeBit<EQ_CPLT_CTRL1_TC_REGION4_FENCE>(l_attr_pg.getBit<24>());
    //CPLT_CTRL1.TC_REGION5_FENCE = l_attr_pg.getBit<25>()
    l_data64.writeBit<EQ_CPLT_CTRL1_TC_REGION5_FENCE>(l_attr_pg.getBit<25>());
    //CPLT_CTRL1.TC_REGION6_FENCE = l_attr_pg.getBit<26>()
    l_data64.writeBit<EQ_CPLT_CTRL1_TC_REGION6_FENCE>(l_attr_pg.getBit<26>());
    //CPLT_CTRL1.TC_REGION7_FENCE = l_attr_pg.getBit<27>()
    l_data64.writeBit<EQ_CPLT_CTRL1_TC_REGION7_FENCE>(l_attr_pg.getBit<27>());
    //CPLT_CTRL1.UNUSED_12B = l_attr_pg.getBit<28>()
    l_data64.writeBit<PEC_CPLT_CTRL1_UNUSED_12B>(l_attr_pg.getBit<28>());
    //CPLT_CTRL1.UNUSED_13B = l_attr_pg.getBit<29>()
    l_data64.writeBit<PEC_CPLT_CTRL1_UNUSED_13B>(l_attr_pg.getBit<29>());
    //CPLT_CTRL1.UNUSED_14B = l_attr_pg.getBit<30>()
    l_data64.writeBit<PEC_CPLT_CTRL1_UNUSED_14B>(l_attr_pg.getBit<30>());
    FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_CPLT_CTRL1_CLEAR, l_data64));

    FAPI_INF("reset abistclk_muxsel and syncclk_muxsel");
    //Setting CPLT_CTRL0 register value
    l_data64.flush<0>();
    //CPLT_CTRL0.CTRL_CC_ABSTCLK_MUXSEL_DC = 1
    l_data64.writeBit<PEC_CPLT_CTRL0_CTRL_CC_ABSTCLK_MUXSEL_DC>(1);
    //CPLT_CTRL0.TC_UNIT_SYNCCLK_MUXSEL_DC = 1
    l_data64.writeBit<PEC_CPLT_CTRL0_TC_UNIT_SYNCCLK_MUXSEL_DC>(1);
    FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_CPLT_CTRL0_CLEAR, l_data64));

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}

/// @brief will force all chiplets out of flush
///
/// @param[in]     i_target_chiplet   Reference to TARGET_TYPE_PERV target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode p9_mem_startclocks_flushmode(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet)
{
    fapi2::buffer<uint64_t> l_data64;
    FAPI_DBG("Entering ...");

    FAPI_INF("Clear flush_inhibit to go in to flush mode");
    //Setting CPLT_CTRL0 register value
    l_data64.flush<0>();
    //CPLT_CTRL0.CTRL_CC_FLUSHMODE_INH_DC = 0
    l_data64.setBit<PEC_CPLT_CTRL0_CTRL_CC_FLUSHMODE_INH_DC>();
    FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_CPLT_CTRL0_CLEAR, l_data64));

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}
<|endoftext|>