<commit_before>#include <QStringList>

#include "kernel.h"
#include "raster.h"
#include "astnode.h"
#include "idnode.h"
#include "kernel.h"
#include "symboltable.h"
#include "operationnode.h"
#include "expressionnode.h"
#include "parametersnode.h"
#include "selectornode.h"
#include "termnode.h"
#include "commandhandler.h"

using namespace Ilwis;

TermNode::TermNode() : _logicalNegation(false), _numericalNegation(false)
{
}

void TermNode::setNumerical(char *num)
{
    QString s(num);
    _content = csNumerical;
    if ( s == "?") {
        _number = Ilwis::rUNDEF;
        return;
    }
    bool ok;
    double b =s.toDouble(&ok);
    _number = b;
    if(!ok) {
        _number = Ilwis::rUNDEF;
    }

}

void TermNode::setId(IDNode *node)
{
    _id = QSharedPointer<IDNode>(node)   ;
    _content = csID;
}

void TermNode::setExpression(ExpressionNode *n)
{
    _expression = QSharedPointer<ExpressionNode>(n);
    _content = csExpression;
}

void TermNode::setString(char *s)
{
    _string = QString(s);
    _content = csString;
}

void TermNode::setParameters(ParametersNode *n)
{
    _parameters = QSharedPointer<ParametersNode>(n);
    _content = csMethod;
}

QString TermNode::nodeType() const
{
    return "term";
}

void TermNode::setLogicalNegation(bool yesno)
{
    _logicalNegation = yesno;
}

void TermNode::setNumericalNegation(bool yesno)
{
    _numericalNegation = yesno;
}

bool TermNode::evaluate(SymbolTable &symbols, int scope, ExecutionContext *ctx)
{
    if ( _content == csExpression)  {
        if (_expression->evaluate(symbols, scope, ctx)) {
            _value = {_expression->value(), NodeValue::ctExpression};
            return true;
        }
    } else if (_content == csNumerical) {
        if ( _numericalNegation)
            _value = {-_number, NodeValue::ctNumerical};
        else
            _value = {_number, NodeValue::ctNumerical};
        return true;

    } else if ( _content == csString) {
        _value = {_string, NodeValue::ctString};
        return true;

    } else if ( _content == csMethod) {
        QString parms = "(";
        for(int i=0; i < _parameters->noOfChilderen(); ++i) {
            bool ok = _parameters->child(i)->evaluate(symbols, scope, ctx);
            if (!ok)
                return false;
            QString name = getName(_parameters->child(i)->value());
            if ( i != 0)
                parms += ",";
            parms += name;

        }
        parms += ")";
        QString expression = _id->id() + parms;
        bool ok = Ilwis::commandhandler()->execute(expression, ctx, symbols);
        if ( !ok || ctx->_results.size() != 1)
            throw ScriptExecutionError(TR("Expression execution error in script; script aborted. See log for further details"));

        _value = {symbols.getValue(ctx->_results[0]), ctx->_results[0], NodeValue::ctMethod};
        return true;

    } else if ( _content == csID) {
        _id->evaluate(symbols, scope, ctx);
        QString value;
        if ( _id->isReference()) {
            if ( symbols.getSymbol(_id->id(),scope).isValid())
                value = _id->id();
            else
                return false;
        }
        else
            value = _id->id();
        if ( _selectors.size() > 0) {
            // selectors are handled by successive calls to the selection operation and in the end giving the temp object to the value
            for(QSharedPointer<Selector> selector: _selectors)  {
                QString selectordef;
                if ( !selector->box().isNull())
                    selectordef = QString("\"box=%1 %2, %3 %4\"").arg(selector->box().min_corner().x()).arg(selector->box().min_corner().y()).
                                                                arg(selector->box().max_corner().x()).arg(selector->box().max_corner().y());
                else if (selector->selectorType() == "index") {
                    selectordef = "\"index=" + selector->variable() + "\"";
                }
                else if ( selector->variable() != sUNDEF)
                    selectordef = "\"attribute=" + selector->variable() + "\"";
                QString outname = ANONYMOUS_PREFIX;
                QString expression = QString("%1=selection(%2,%3)").arg(outname).arg(value).arg(selectordef);
                if(!Ilwis::commandhandler()->execute(expression, ctx, symbols)) {
                    throw ScriptExecutionError(TR("Expression execution error in script; script aborted. See log for further details"));
                }
                QString outgc = ctx->_results[0];
                value = outgc;
            }
        }
        _value = {value, NodeValue::ctID};
        return value != "" && value != sUNDEF;

    }
    return false;
}

QString TermNode::getName(const NodeValue& var) const {
    QString name = var.toString();
    if (name != sUNDEF)
        return name;
//    QString typeName = var.typeName();
//    if ( typeName == "Ilwis::IRasterCoverage") {
//        Ilwis::IRasterCoverage raster = var.value<Ilwis::IRasterCoverage>();
//        name = raster->name();
//    }
//    if ( typeName == "Coordinate") {
//        name = var.id();
//    }
//    if ( typeName == "Voxel") {
//        name = var.id();
//    }
    return var.id();
}

void TermNode::addSelector(Selector *n)
{
    _selectors.push_back(QSharedPointer<Selector>(n));
}
<commit_msg>added support for column/record ranges<commit_after>#include <QStringList>

#include "kernel.h"
#include "raster.h"
#include "astnode.h"
#include "idnode.h"
#include "kernel.h"
#include "symboltable.h"
#include "operationnode.h"
#include "expressionnode.h"
#include "parametersnode.h"
#include "selectornode.h"
#include "termnode.h"
#include "commandhandler.h"

using namespace Ilwis;

TermNode::TermNode() : _logicalNegation(false), _numericalNegation(false)
{
}

void TermNode::setNumerical(char *num)
{
    QString s(num);
    _content = csNumerical;
    if ( s == "?") {
        _number = Ilwis::rUNDEF;
        return;
    }
    bool ok;
    double b =s.toDouble(&ok);
    _number = b;
    if(!ok) {
        _number = Ilwis::rUNDEF;
    }

}

void TermNode::setId(IDNode *node)
{
    _id = QSharedPointer<IDNode>(node)   ;
    _content = csID;
}

void TermNode::setExpression(ExpressionNode *n)
{
    _expression = QSharedPointer<ExpressionNode>(n);
    _content = csExpression;
}

void TermNode::setString(char *s)
{
    _string = QString(s);
    _content = csString;
}

void TermNode::setParameters(ParametersNode *n)
{
    _parameters = QSharedPointer<ParametersNode>(n);
    _content = csMethod;
}

QString TermNode::nodeType() const
{
    return "term";
}

void TermNode::setLogicalNegation(bool yesno)
{
    _logicalNegation = yesno;
}

void TermNode::setNumericalNegation(bool yesno)
{
    _numericalNegation = yesno;
}

bool TermNode::evaluate(SymbolTable &symbols, int scope, ExecutionContext *ctx)
{
    if ( _content == csExpression)  {
        if (_expression->evaluate(symbols, scope, ctx)) {
            _value = {_expression->value(), NodeValue::ctExpression};
            return true;
        }
    } else if (_content == csNumerical) {
        if ( _numericalNegation)
            _value = {-_number, NodeValue::ctNumerical};
        else
            _value = {_number, NodeValue::ctNumerical};
        return true;

    } else if ( _content == csString) {
        _value = {_string, NodeValue::ctString};
        return true;

    } else if ( _content == csMethod) {
        QString parms = "(";
        for(int i=0; i < _parameters->noOfChilderen(); ++i) {
            bool ok = _parameters->child(i)->evaluate(symbols, scope, ctx);
            if (!ok)
                return false;
            QString name = getName(_parameters->child(i)->value());
            if ( i != 0)
                parms += ",";
            parms += name;

        }
        parms += ")";
        QString expression = _id->id() + parms;
        bool ok = Ilwis::commandhandler()->execute(expression, ctx, symbols);
        if ( !ok || ctx->_results.size() != 1)
            throw ScriptExecutionError(TR("Expression execution error in script; script aborted. See log for further details"));

        _value = {symbols.getValue(ctx->_results[0]), ctx->_results[0], NodeValue::ctMethod};
        return true;

    } else if ( _content == csID) {
        _id->evaluate(symbols, scope, ctx);
        QString value;
        if ( _id->isReference()) {
            if ( symbols.getSymbol(_id->id(),scope).isValid())
                value = _id->id();
            else
                return false;
        }
        else
            value = _id->id();
        if ( _selectors.size() > 0) {
            // selectors are handled by successive calls to the selection operation and in the end giving the temp object to the value
            for(QSharedPointer<Selector> selector: _selectors)  {
                QString selectordef;
                if ( !selector->box().isNull())
                    selectordef = QString("\"box=%1 %2, %3 %4\"").arg(selector->box().min_corner().x()).arg(selector->box().min_corner().y()).
                                                                arg(selector->box().max_corner().x()).arg(selector->box().max_corner().y());
                else if (selector->selectorType() == "index") {
                    selectordef = "\"index=" + selector->variable() + "\"";
                } else if (selector->selectorType() == "columnrange") {
                    selectordef = QString("\"columnrange=%1,%2").arg(selector->beginCol()).arg(selector->endCol());
                    if ( selector->keyColumns() != sUNDEF)
                        selectordef += "," + selector->keyColumns();
                    selectordef += "\"";
                }else if (selector->selectorType() == "recordrange") {
                    selectordef = QString("\"recordrange=%1,%2").arg(selector->beginRec()).arg(selector->endRec());
                    selectordef += "\"";
                }else if (selector->selectorType() == "columnrecordrange") {
                    selectordef = QString("\"columnrecordrange=%1,%2,%3, %4").arg(selector->beginCol()).
                                                                              arg(selector->endCol()).
                                                                              arg(selector->beginRec()).
                                                                              arg(selector->endRec());
                    if ( selector->keyColumns() != sUNDEF)
                        selectordef += "," + selector->keyColumns();
                    selectordef += "\"";
                }
                else if ( selector->variable() != sUNDEF)
                    selectordef = "\"attribute=" + selector->variable() + "\"";
                QString outname = ANONYMOUS_PREFIX;
                QString expression = QString("%1=selection(%2,%3)").arg(outname).arg(value).arg(selectordef);
                if(!Ilwis::commandhandler()->execute(expression, ctx, symbols)) {
                    throw ScriptExecutionError(TR("Expression execution error in script; script aborted. See log for further details"));
                }
                QString outgc = ctx->_results[0];
                value = outgc;
            }
        }
        _value = {value, NodeValue::ctID};
        return value != "" && value != sUNDEF;

    }
    return false;
}

QString TermNode::getName(const NodeValue& var) const {
    QString name = var.toString();
    if (name != sUNDEF)
        return name;
//    QString typeName = var.typeName();
//    if ( typeName == "Ilwis::IRasterCoverage") {
//        Ilwis::IRasterCoverage raster = var.value<Ilwis::IRasterCoverage>();
//        name = raster->name();
//    }
//    if ( typeName == "Coordinate") {
//        name = var.id();
//    }
//    if ( typeName == "Voxel") {
//        name = var.id();
//    }
    return var.id();
}

void TermNode::addSelector(Selector *n)
{
    _selectors.push_back(QSharedPointer<Selector>(n));
}
<|endoftext|>


<commit_before>/* lorina: C++ parsing library
 * Copyright (C) 2018  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/*!
  \file blif.hpp
  \brief Implements blif parser

  \author Heinz Riener
*/

#pragma once

#include <lorina/common.hpp>
#include <lorina/diagnostics.hpp>
#include <lorina/detail/utils.hpp>
#include <regex>
#include <iostream>

namespace lorina
{

/*! \brief A reader visitor for the BLIF format.
 *
 * Callbacks for the BLIF (Berkeley Logic Interchange Format) format.
 */
class blif_reader
{
public:
  /*! \brief Type of the output cover as truth table. */
  using output_cover_t = std::vector<std::pair<std::string, std::string>>;

public:
  /*! \brief Callback method for parsed model.
   *
   * \param model_name Name of the model
   */
  virtual void on_model( const std::string& model_name ) const
  {
    (void)model_name;
  }

  /*! \brief Callback method for parsed input.
   *
   * \param name Input name
   */
  virtual void on_input( const std::string& name ) const
  {
    (void)name;
  }

  /*! \brief Callback method for parsed output.
   *
   * \param name Output name
   */
  virtual void on_output( const std::string& name ) const
  {
    (void)name;
  }

  /*! \brief Callback method for parsed gate.
   *
   * \param inputs A list of input names
   * \param output Name of output of the gate
   * \param cover N-input, 1-output PLA description of the logic function corresponding to the logic gate
   */
  virtual void on_gate( const std::vector<std::string>& inputs, const std::string& output, const output_cover_t& cover ) const
  {
    (void)inputs;
    (void)output;
    (void)cover;
  }

  /*! \brief Callback method for parsed end.
   *
   */
  virtual void on_end() const {}

  /*! \brief Callback method for parsed comment.
   *
   * \param comment Comment
   */
  virtual void on_comment( const std::string& comment ) const
  {
    (void)comment;
  }
}; /* blif_reader */

/*! \brief A BLIF reader for prettyprinting BLIF.
 *
 * Callbacks for prettyprinting of BLIF.
 *
 */
class blif_pretty_printer : public blif_reader
{
public:
  /*! \brief Constructor of the BLIF pretty printer.
   *
   * \param os Output stream
   */
  blif_pretty_printer( std::ostream& os = std::cout )
      : _os( os )
  {
  }

  virtual void on_model( const std::string& model_name ) const
  {
    _os << ".model " << model_name << std::endl;
  }

  virtual void on_input( const std::string& name ) const
  {
    if ( first_input ) _os << std::endl << ".inputs ";
    _os << name << " ";
    first_input = false;
  }

  virtual void on_output( const std::string& name ) const
  {
    if ( first_output ) _os << std::endl << ".output ";
    _os << name << " ";
    first_output = false;
  }

  virtual void on_gate( const std::vector<std::string>& inputs, const std::string& output, const output_cover_t& cover ) const
  {
    _os << std::endl << fmt::format( ".names {0} {1}", detail::join( inputs, "," ), output ) << std::endl;
    for ( const auto& c : cover )
    {
      _os << c.first << ' ' << c.second << std::endl;
    }
  }

  virtual void on_end() const
  {
    _os << std::endl << ".end" << std::endl;
  }

  virtual void on_comment( const std::string& comment ) const
  {
    _os << std::endl << "# " << comment << std::endl;
  }

  mutable bool first_input = true; /*!< Predicate that is true until the first input was parsed */
  mutable bool first_output = true; /*!< Predicate that is true until the first output was parsed */
  std::ostream& _os; /*!< Output stream */
}; /* blif_pretty_printer */

namespace blif_regex
{
static std::regex model( R"(.model\s+(.*))" );
static std::regex inputs( R"(.inputs\s+(.*))" );
static std::regex outputs( R"(.outputs\s+(.*))" );
static std::regex names( R"(.names\s+(.*))" );
static std::regex line_of_truthtable( R"(([01\-]*)\s*([01\-]))" );
static std::regex end( R"(.end)" );
} // namespace blif_regex

/*! \brief Reader function for the BLIF format.
 *
 * Reads BLIF format from a stream and invokes a callback
 * method for each parsed primitive and each detected parse error.
 *
 * \param in Input stream
 * \param reader A BLIF reader with callback methods invoked for parsed primitives
 * \param diag An optional diagnostic engine with callback methods for parse errors
 * \return Success if parsing have been successful, or parse error if parsing have failed
 */
inline return_code read_blif( std::istream& in, const blif_reader& reader, diagnostic_engine* diag = nullptr )
{
  return_code result = return_code::success;

  std::smatch m;
  detail::foreach_line_in_file_escape( in, [&]( std::string line ) {
    redo:
      /* empty line or comment */
      if ( line.empty() || line[0] == '#' )
        return true;

      /* names */
      if ( std::regex_search( line, m, blif_regex::names ) )
      {
        auto args = detail::split( detail::trim_copy( m[1] ), " " );
        const auto output = *( args.rbegin() );
        args.pop_back();

        std::vector<std::pair<std::string, std::string>> tt;
        std::string copy_line;
        detail::foreach_line_in_file_escape( in, [&]( const std::string& line ) {
          copy_line = line;

          /* terminate when the next '.' declaration starts */
          if ( line[0] == '.' )
            return false;

          /* empty line or comment */
          if ( line.empty() || line[0] == '#' )
            return true;

          if ( std::regex_search( line, m, blif_regex::line_of_truthtable ) )
          {
            tt.push_back( std::make_pair( detail::trim_copy( m[1] ), detail::trim_copy( m[2] ) ) );
            return true;
          }

          return false;
        } );

        reader.on_gate( args, output, tt );

        if ( in.eof() )
        {
          return true;
        }
        else
        {
          /* restart parsing with the line of the subparser */
          line = copy_line;
          goto redo;
        }
      }

      /* .model <string> */
      if ( std::regex_search( line, m, blif_regex::model ) )
      {
        reader.on_model( detail::trim_copy( m[1] ) );
        return true;
      }

      /* .inputs <list of whitespace separated strings> */
      if ( std::regex_search( line, m, blif_regex::inputs ) )
      {
        for ( const auto& input : detail::split( detail::trim_copy( m[1] ), " " ) )
        {
          reader.on_input( detail::trim_copy( input ) );
        }
        return true;
      }

      /* .outputs <list of whitespace separated strings> */
      if ( std::regex_search( line, m, blif_regex::outputs ) )
      {
        for ( const auto& output : detail::split( detail::trim_copy( m[1] ), " " ) )
        {
          reader.on_output( detail::trim_copy( output ) );
        }
        return true;
      }

      /* .end */
      if ( std::regex_search( line, m, blif_regex::end ) )
      {
        reader.on_end();
        return true;
      }

      if ( diag )
      {
        diag->report( diagnostic_level::error,
                      fmt::format( "cannot parse line `{0}`", line ) );
      }

      result = return_code::parse_error;
      return true;
  } );

  return result;
}

/*! \brief Reader function for BLIF format.
 *
 * Reads binary BLIF format from a file and invokes a callback
 * method for each parsed primitive and each detected parse error.
 *
 * \param filename Name of the file
 * \param reader A BLIF reader with callback methods invoked for parsed primitives
 * \param diag An optional diagnostic engine with callback methods for parse errors
 * \return Success if parsing have been successful, or parse error if parsing have failed
 */
inline return_code read_blif( const std::string& filename, const blif_reader& reader, diagnostic_engine* diag = nullptr )
{
  std::ifstream in( detail::word_exp_filename( filename ), std::ifstream::in );
  return read_blif( in, reader, diag );
}

} // namespace lorina
<commit_msg>blif_reader: topological sorting (attempt to restore commit af8bac8636d9017ccdee7259c84f6a75cf4e5fab). (#201)<commit_after>/* lorina: C++ parsing library
 * Copyright (C) 2018  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/*!
  \file blif.hpp
  \brief Implements blif parser

  \author Heinz Riener
*/

#pragma once

#include <lorina/common.hpp>
#include <lorina/diagnostics.hpp>
#include <lorina/detail/utils.hpp>
#include <regex>
#include <iostream>

namespace lorina
{

/*! \brief A reader visitor for the BLIF format.
 *
 * Callbacks for the BLIF (Berkeley Logic Interchange Format) format.
 */
class blif_reader
{
public:
  /*! \brief Type of the output cover as truth table. */
  using output_cover_t = std::vector<std::pair<std::string, std::string>>;

public:
  /*! \brief Callback method for parsed model.
   *
   * \param model_name Name of the model
   */
  virtual void on_model( const std::string& model_name ) const
  {
    (void)model_name;
  }

  /*! \brief Callback method for parsed input.
   *
   * \param name Input name
   */
  virtual void on_input( const std::string& name ) const
  {
    (void)name;
  }

  /*! \brief Callback method for parsed output.
   *
   * \param name Output name
   */
  virtual void on_output( const std::string& name ) const
  {
    (void)name;
  }

  /*! \brief Callback method for parsed gate.
   *
   * \param inputs A list of input names
   * \param output Name of output of the gate
   * \param cover N-input, 1-output PLA description of the logic function corresponding to the logic gate
   */
  virtual void on_gate( const std::vector<std::string>& inputs, const std::string& output, const output_cover_t& cover ) const
  {
    (void)inputs;
    (void)output;
    (void)cover;
  }

  /*! \brief Callback method for parsed end.
   *
   */
  virtual void on_end() const {}

  /*! \brief Callback method for parsed comment.
   *
   * \param comment Comment
   */
  virtual void on_comment( const std::string& comment ) const
  {
    (void)comment;
  }
}; /* blif_reader */

/*! \brief A BLIF reader for prettyprinting BLIF.
 *
 * Callbacks for prettyprinting of BLIF.
 *
 */
class blif_pretty_printer : public blif_reader
{
public:
  /*! \brief Constructor of the BLIF pretty printer.
   *
   * \param os Output stream
   */
  blif_pretty_printer( std::ostream& os = std::cout )
      : _os( os )
  {
  }

  virtual void on_model( const std::string& model_name ) const
  {
    _os << ".model " << model_name << std::endl;
  }

  virtual void on_input( const std::string& name ) const
  {
    if ( first_input ) _os << std::endl << ".inputs ";
    _os << name << " ";
    first_input = false;
  }

  virtual void on_output( const std::string& name ) const
  {
    if ( first_output ) _os << std::endl << ".output ";
    _os << name << " ";
    first_output = false;
  }

  virtual void on_gate( const std::vector<std::string>& inputs, const std::string& output, const output_cover_t& cover ) const
  {
    _os << std::endl << fmt::format( ".names {0} {1}", detail::join( inputs, "," ), output ) << std::endl;
    for ( const auto& c : cover )
    {
      _os << c.first << ' ' << c.second << std::endl;
    }
  }

  virtual void on_end() const
  {
    _os << std::endl << ".end" << std::endl;
  }

  virtual void on_comment( const std::string& comment ) const
  {
    _os << std::endl << "# " << comment << std::endl;
  }

  mutable bool first_input = true; /*!< Predicate that is true until the first input was parsed */
  mutable bool first_output = true; /*!< Predicate that is true until the first output was parsed */
  std::ostream& _os; /*!< Output stream */
}; /* blif_pretty_printer */

namespace blif_regex
{
static std::regex model( R"(.model\s+(.*))" );
static std::regex inputs( R"(.inputs\s+(.*))" );
static std::regex outputs( R"(.outputs\s+(.*))" );
static std::regex names( R"(.names\s+(.*))" );
static std::regex line_of_truthtable( R"(([01\-]*)\s*([01\-]))" );
static std::regex end( R"(.end)" );
} // namespace blif_regex

/*! \brief Reader function for the BLIF format.
 *
 * Reads BLIF format from a stream and invokes a callback
 * method for each parsed primitive and each detected parse error.
 *
 * \param in Input stream
 * \param reader A BLIF reader with callback methods invoked for parsed primitives
 * \param diag An optional diagnostic engine with callback methods for parse errors
 * \return Success if parsing have been successful, or parse error if parsing have failed
 */
inline return_code read_blif( std::istream& in, const blif_reader& reader, diagnostic_engine* diag = nullptr )
{
  return_code result = return_code::success;

  const auto dispatch_function = [&]( std::vector<std::string> inputs, std::string output, std::vector<std::pair<std::string, std::string>> tt )
    {
      reader.on_gate( inputs, output, tt );
    };

  detail::call_in_topological_order<std::vector<std::string>, std::string, std::vector<std::pair<std::string, std::string>>> on_action( dispatch_function );

  std::smatch m;
  detail::foreach_line_in_file_escape( in, [&]( std::string line ) {
    redo:
      /* empty line or comment */
      if ( line.empty() || line[0] == '#' )
        return true;

      /* names */
      if ( std::regex_search( line, m, blif_regex::names ) )
      {
        auto args = detail::split( detail::trim_copy( m[1] ), " " );
        const auto output = *( args.rbegin() );
        args.pop_back();

        std::vector<std::pair<std::string, std::string>> tt;
        std::string copy_line;
        detail::foreach_line_in_file_escape( in, [&]( const std::string& line ) {
          copy_line = line;

          /* terminate when the next '.' declaration starts */
          if ( line[0] == '.' )
            return false;

          /* empty line or comment */
          if ( line.empty() || line[0] == '#' )
            return true;

          if ( std::regex_search( line, m, blif_regex::line_of_truthtable ) )
          {
            tt.push_back( std::make_pair( detail::trim_copy( m[1] ), detail::trim_copy( m[2] ) ) );
            return true;
          }

          return false;
        } );

        on_action.call_deferred( args, output, args, output, tt );

        if ( in.eof() )
        {
          return true;
        }
        else
        {
          /* restart parsing with the line of the subparser */
          line = copy_line;
          goto redo;
        }
      }

      /* .model <string> */
      if ( std::regex_search( line, m, blif_regex::model ) )
      {
        reader.on_model( detail::trim_copy( m[1] ) );
        return true;
      }

      /* .inputs <list of whitespace separated strings> */
      if ( std::regex_search( line, m, blif_regex::inputs ) )
      {
        for ( const auto& input : detail::split( detail::trim_copy( m[1] ), " " ) )
        {
          auto const s = detail::trim_copy( input );
          on_action.declare_known( s );
          reader.on_input( s );
        }
        return true;
      }

      /* .outputs <list of whitespace separated strings> */
      if ( std::regex_search( line, m, blif_regex::outputs ) )
      {
        for ( const auto& output : detail::split( detail::trim_copy( m[1] ), " " ) )
        {
          reader.on_output( detail::trim_copy( output ) );
        }
        return true;
      }

      /* .end */
      if ( std::regex_search( line, m, blif_regex::end ) )
      {
        reader.on_end();
        return true;
      }

      if ( diag )
      {
        diag->report( diagnostic_level::error,
                      fmt::format( "cannot parse line `{0}`", line ) );
      }

      result = return_code::parse_error;
      return true;
  } );

  return result;
}

/*! \brief Reader function for BLIF format.
 *
 * Reads binary BLIF format from a file and invokes a callback
 * method for each parsed primitive and each detected parse error.
 *
 * \param filename Name of the file
 * \param reader A BLIF reader with callback methods invoked for parsed primitives
 * \param diag An optional diagnostic engine with callback methods for parse errors
 * \return Success if parsing have been successful, or parse error if parsing have failed
 */
inline return_code read_blif( const std::string& filename, const blif_reader& reader, diagnostic_engine* diag = nullptr )
{
  std::ifstream in( detail::word_exp_filename( filename ), std::ifstream::in );
  return read_blif( in, reader, diag );
}

} // namespace lorina
<|endoftext|>


<commit_before>#include <map>
#include <unordered_map>
#include <memory>
#include <gtest/gtest.h>
#include "mmap_allocator.h"

using std::equal_to;
using std::hash;
using std::less;
using std::map;
using std::pair;
using std::string;
using std::to_string;
using std::unordered_map;
using std::unique_ptr;

class MMapAllocatorTest : public testing::Test {
 protected:
  template <class T>
  unique_ptr<MMapAllocator<T>> make_allocator() {
    return unique_ptr<MMapAllocator<T>>(MMapAllocator<T>::New("test.db"));
  }

  template <class T>
  std::vector<T, MMapAllocator<T>> make_vector(MMapAllocator<T>* alloc) {
    return std::vector<T, MMapAllocator<T>>(*alloc);
  }
};

TEST_F(MMapAllocatorTest, VectorInt) {
  auto alloc = make_allocator<int>();
  ASSERT_FALSE(alloc.get() == NULL);
  auto vec = make_vector<int>(alloc.get());

  for (int i = 0; i < 10; ++i) {
    vec.push_back(i);
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(i, vec[i]);
  }
}

TEST_F(MMapAllocatorTest, VectorIntInitialized) {
  auto alloc = make_allocator<int>();
  ASSERT_FALSE(alloc.get() == NULL);
  std::vector<int, MMapAllocator<int>> vec({4, 42, 24, 7}, *alloc);

  EXPECT_EQ(4, vec.size());
  EXPECT_EQ(4, vec[0]);
  EXPECT_EQ(42, vec[1]);
  EXPECT_EQ(24, vec[2]);
  EXPECT_EQ(7, vec[3]);
}

TEST_F(MMapAllocatorTest, VectorDouble) {
  auto alloc = make_allocator<double>();
  ASSERT_FALSE(alloc.get() == NULL);
  auto vec = make_vector<double>(alloc.get());

  for (int i = 0; i < 10; ++i) {
    vec.push_back(sqrt(i));
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(sqrt(i), vec[i]);
  }
}

TEST_F(MMapAllocatorTest, VectorString) {
  auto alloc = make_allocator<string>();
  ASSERT_FALSE(alloc.get() == NULL);
  auto vec = make_vector<string>(alloc.get());

  for (int i = 0; i < 10; ++i) {
    vec.push_back("Hello, world!");
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ("Hello, world!", vec[i]);
  }
}

TEST_F(MMapAllocatorTest, MapStringString) {
  auto alloc = make_allocator<pair<const string, string>>();
  ASSERT_FALSE(alloc.get() == NULL);
  map<string, string, less<string>, MMapAllocator<pair<const string, string>>>
      m(less<string>(), *alloc);

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(MMapAllocatorTest, HashStringString) {
  auto alloc = make_allocator<pair<const string, string>>();
  ASSERT_FALSE(alloc.get() == NULL);
  unordered_map<string, string, hash<string>, equal_to<string>,
                MMapAllocator<pair<const string, string>>> m(10, hash<string>(),
                                                             equal_to<string>(),
                                                             *alloc);

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(MMapAllocatorTest, Nested) {
  using Vector = std::vector<string, MMapAllocator<string>>;
  using Hash =
      std::unordered_map<string, Vector, hash<string>, equal_to<string>,
                         MMapAllocator<pair<const string, Vector>>>;

  unique_ptr<Hash::allocator_type> hash_alloc(
      Hash::allocator_type::New("test.db"));
  Vector::allocator_type vector_alloc(*hash_alloc);

  auto m = Hash(10, hash<string>(), equal_to<string>(), *hash_alloc);
  EXPECT_EQ(0, m.size());

  m.insert(make_pair("foo", Vector(vector_alloc)));
  EXPECT_EQ(1, m.size());
  m.insert(make_pair("bar", Vector(vector_alloc)));
  EXPECT_EQ(2, m.size());

  EXPECT_EQ(0, m.at("foo").size());
  for (int i = 0; i < 10; ++i) {
    m.at("foo").push_back(to_string(i));
  }
  EXPECT_EQ(10, m.at("foo").size());

  EXPECT_EQ(0, m.at("bar").size());
  for (int i = 0; i < 10; ++i) {
    m.at("bar").push_back(to_string(i * i));
  }
  EXPECT_EQ(10, m.at("bar").size());

  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i), m.at("foo")[i]);
  }
  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i * i), m.at("bar")[i]);
  }
}
<commit_msg>updated mmap_allocator_test.cc<commit_after>#include <map>
#include <unordered_map>
#include <gtest/gtest.h>
#include "mmap_allocator.h"

using std::string;
using std::to_string;

namespace mm {

class AllocatorTest : public testing::Test {
 protected:
  void SetUp() { SetDefault("test.db"); }
  void TearDown() { FreeDefault(); }
};

TEST_F(AllocatorTest, VectorInt) {
  vector<int> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(i);
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(i, vec[i]);
  }
}

TEST_F(AllocatorTest, VectorIntInitialized) {
  vector<int> vec{4, 42, 24, 7};

  EXPECT_EQ(4, vec.size());
  EXPECT_EQ(4, vec[0]);
  EXPECT_EQ(42, vec[1]);
  EXPECT_EQ(24, vec[2]);
  EXPECT_EQ(7, vec[3]);
}

TEST_F(AllocatorTest, VectorDouble) {
  vector<double> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back(sqrt(i));
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ(sqrt(i), vec[i]);
  }
}

TEST_F(AllocatorTest, VectorString) {
  vector<string> vec;

  for (int i = 0; i < 10; ++i) {
    vec.push_back("Hello, world!");
  }

  EXPECT_EQ(10, vec.size());

  for (int i = 0; i < vec.size(); ++i) {
    EXPECT_EQ("Hello, world!", vec[i]);
  }
}

TEST_F(AllocatorTest, MapStringString) {
  map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, SetString) {
  set<string> s;

  s.insert("foo");
  s.insert("bar");

  EXPECT_EQ(2, s.size());
  EXPECT_EQ(1, s.count("foo"));
  EXPECT_EQ(1, s.count("bar"));
  EXPECT_EQ(0, s.count("baz"));
}

TEST_F(AllocatorTest, HashStringString) {
  unordered_map<string, string> m;

  m["Hello"] = "World";
  m["Goodbye"] = "All";
  m["2+2"] = "4";

  EXPECT_EQ(3, m.size());
  EXPECT_EQ("World", m["Hello"]);
}

TEST_F(AllocatorTest, Nested) {
  unordered_map<string, vector<string>> m;
  EXPECT_EQ(0, m.size());

  for (int i = 0; i < 10; ++i) {
    m["foo"].push_back(to_string(i));
  }
  EXPECT_EQ(10, m["foo"].size());

  for (int i = 0; i < 10; ++i) {
    m["bar"].push_back(to_string(i * i));
  }
  EXPECT_EQ(10, m["bar"].size());

  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i), m["foo"][i]);
  }
  for (int i = 0; i < 10; ++i) {
    EXPECT_EQ(to_string(i * i), m["bar"][i]);
  }
}

};  // namespace mm
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "ProcessRunner.h"
#include "Environment.h"
#include "ProcessWithLogon.h"
#include "StreamWriter.h"

Result<ExitCode> ProcessRunner::Run(Settings settings) const
{
	// Get environment of parent process
	auto parentProcessEnvironmentResult = Environment::CreateForCurrentProcess();
	if (parentProcessEnvironmentResult.HasError())
	{
		return Result<ExitCode>(parentProcessEnvironmentResult.GetErrorCode(), parentProcessEnvironmentResult.GetErrorDescription());
	}

	auto parentProcessEnvironment = parentProcessEnvironmentResult.GetResultValue();
	Environment defaultEnvironment;

	// Run process
	auto newProcessEnvironment = settings.GetInheritEnvironment() ? parentProcessEnvironment : defaultEnvironment;
	StreamWriter stdOutput(GetStdHandle(STD_OUTPUT_HANDLE));
	StreamWriter stdError(GetStdHandle(STD_ERROR_HANDLE));
	ProcessTracker processTracker(stdOutput, stdError);

	ProcessAsUser processAsUserToRun;
	auto runResult = processAsUserToRun.Run(settings, newProcessEnvironment, processTracker);
	if (!runResult.HasError())
	{
		return runResult.GetResultValue();
	}

	ProcessWithLogon processWithLogonToRun;
	return processWithLogonToRun.Run(settings, newProcessEnvironment, processTracker);
}<commit_msg>Try to run with logon when exit code equ status_dll_init_failed<commit_after>#include "stdafx.h"
#include "ProcessRunner.h"
#include "Environment.h"
#include "ProcessWithLogon.h"
#include "StreamWriter.h"

Result<ExitCode> ProcessRunner::Run(Settings settings) const
{
	// Get environment of parent process
	auto parentProcessEnvironmentResult = Environment::CreateForCurrentProcess();
	if (parentProcessEnvironmentResult.HasError())
	{
		return Result<ExitCode>(parentProcessEnvironmentResult.GetErrorCode(), parentProcessEnvironmentResult.GetErrorDescription());
	}

	auto parentProcessEnvironment = parentProcessEnvironmentResult.GetResultValue();
	Environment defaultEnvironment;

	// Run process
	auto newProcessEnvironment = settings.GetInheritEnvironment() ? parentProcessEnvironment : defaultEnvironment;
	StreamWriter stdOutput(GetStdHandle(STD_OUTPUT_HANDLE));
	StreamWriter stdError(GetStdHandle(STD_ERROR_HANDLE));
	ProcessTracker processTracker(stdOutput, stdError);

	ProcessAsUser processAsUserToRun;
	auto runResult = processAsUserToRun.Run(settings, newProcessEnvironment, processTracker);
	if (!runResult.HasError() && runResult.GetResultValue() != STATUS_DLL_INIT_FAILED)
	{
		return runResult.GetResultValue();
	}

	ProcessWithLogon processWithLogonToRun;
	return processWithLogonToRun.Run(settings, newProcessEnvironment, processTracker);
}<|endoftext|>


<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <atomic>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <tuple>

#include <boost/functional/hash.hpp>

#include <dlfcn.h>
#include <unistd.h>
#include <link.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

using Trace = vector<unw_word_t>;

namespace std {
    template<>
    struct hash<Trace>
    {
        size_t operator() (const Trace& trace) const
        {
            size_t seed = 0;
            for (auto ip : trace) {
                boost::hash_combine(seed, ip);
            }
            return seed;
        }
    };
}

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

thread_local Trace traceBuffer;

void trace(const int skip = 2)
{
    traceBuffer.clear();

    const size_t MAX_TRACE_SIZE = 64;
    traceBuffer.reserve(MAX_TRACE_SIZE);

    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip functions we are not interested in
    for (int i = 0; i < skip; ++i) {
        if (unw_step(&cursor) <= 0) {
            return;
        }
    }

    while (unw_step(&cursor) > 0 && traceBuffer.size() < MAX_TRACE_SIZE) {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        traceBuffer.push_back(ip);
    }
}

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

struct Module
{
    string fileName;
    uintptr_t baseAddress;
    uint32_t size;
    unsigned int id;
    bool isExe;

    bool operator<(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) < make_tuple(module.baseAddress, module.size, module.fileName);
    }
    bool operator!=(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) != make_tuple(module.baseAddress, module.size, module.fileName);
    }
};

struct Data
{
    Data()
    {
        modules.reserve(32);
        ipCache.reserve(65536);
        traceCache.reserve(16384);
        allocationInfo.reserve(16384);

        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid());
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        unsetenv("DUMP_MALLOC_TRACE_OUTPUT");
        unsetenv("LD_PRELOAD");
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        fclose(out);
    }

    void updateModuleCache()
    {
        // check list of loaded modules for unknown ones
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        auto& modules = data->modules;
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (modules.empty()) {
                isExe = true;
                ssize_t ret =  readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        uintptr_t addressStart = 0;
        uintptr_t addressEnd = 0;

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                if (addressEnd == 0) {
                    addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                    addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                } else {
                    uintptr_t addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
                    if (addr > addressEnd) {
                        addressEnd = addr;
                    }
                }
            }
        }

        Module module{fileName, addressStart, static_cast<uint32_t>(addressEnd - addressStart), 0, isExe};

        auto it = lower_bound(modules.begin(), modules.end(), module);
        if (it == modules.end() || *it != module) {
            module.id = data->next_module_id++;
            fprintf(data->out, "m %u %s %lx %d\n", module.id, module.fileName.c_str(), module.baseAddress, module.isExe);
            modules.insert(it, module);
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        trace();

        lock_guard<mutex> lock(m_mutex);
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        auto it = traceCache.find(traceBuffer);
        if (it == traceCache.end()) {
            // cache before converting
            auto traceId = next_trace_id++;
            it = traceCache.insert(it, {traceBuffer, traceId});
            // ensure ip cache is up2date
            for (auto& ip : traceBuffer) {
                auto ipIt = ipCache.find(ip);
                if (ipIt == ipCache.end()) {
                    // find module and offset from cache
                    auto module = lower_bound(modules.begin(), modules.end(), ip,
                                                [] (const Module& module, const unw_word_t addr) -> bool {
                                                    return module.baseAddress + module.size < addr;
                                                });
                    if (module == modules.end()) {
                        ip = numeric_limits<unsigned int>::max();
                        continue;
                    }
                    auto ipId = next_ipCache_id++;
                    fprintf(out, "i %u %u %lx\n", ipId, module->id, ip - module->baseAddress);
                    ipIt = ipCache.insert(ipIt, {ip, ipId});
                }
                ip = ipIt->second;
            }
            // print trace
            fprintf(out, "t %u ", traceId);
            for (auto ipId : traceBuffer) {
                if (ipId == numeric_limits<unsigned int>::max()) {
                    continue;
                }
                fprintf(out, "%lu ", ipId);
            }
            fputc('\n', out);
        }
        allocationInfo[ptr] = {size, it->second};
        fprintf(out, "+ %lu %u\n", size, it->second);
    }

    void handleFree(void* ptr)
    {
        lock_guard<mutex> lock(m_mutex);
        auto it = allocationInfo.find(ptr);
        if (it == allocationInfo.end()) {
            return;
        }
        fprintf(out, "- %lu %u\n", it->second.size, it->second.traceId);
        allocationInfo.erase(it);
    }

    mutex m_mutex;
    unsigned int next_module_id = 0;
    unsigned int next_thread_id = 0;
    unsigned int next_ipCache_id = 0;
    unsigned int next_trace_id = 0;

    vector<Module> modules;
    unordered_map<unw_word_t, unw_word_t> ipCache;
    unordered_map<vector<unw_word_t>, unsigned int> traceCache;
    struct AllocationInfo
    {
        size_t size;
        unsigned int traceId;
    };
    unordered_map<void*, AllocationInfo> allocationInfo;
    FILE* out = nullptr;
};

unique_ptr<Data> data;

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    if (data || HandleGuard::inHandler) {
        fprintf(stderr, "initialization recursion detected\n");
        abort();
    }

    HandleGuard guard;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_dlopen = findReal<dlopen_t>("dlopen");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    data.reset(new Data);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (ptr && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<commit_msg>Take trace size into account for hash generation.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdlib>

#include <atomic>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <tuple>

#include <boost/functional/hash.hpp>

#include <dlfcn.h>
#include <unistd.h>
#include <link.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>

using namespace std;

using Trace = vector<unw_word_t>;

namespace std {
    template<>
    struct hash<Trace>
    {
        size_t operator() (const Trace& trace) const
        {
            size_t seed = 0;
            for (auto ip : trace) {
                boost::hash_combine(seed, ip);
            }
            boost::hash_combine(seed, trace.size());
            return seed;
        }
    };
}

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

thread_local Trace traceBuffer;

void trace(const int skip = 2)
{
    traceBuffer.clear();

    const size_t MAX_TRACE_SIZE = 64;
    traceBuffer.reserve(MAX_TRACE_SIZE);

    unw_context_t uc;
    unw_getcontext (&uc);

    unw_cursor_t cursor;
    unw_init_local (&cursor, &uc);

    // skip functions we are not interested in
    for (int i = 0; i < skip; ++i) {
        if (unw_step(&cursor) <= 0) {
            return;
        }
    }

    while (unw_step(&cursor) > 0 && traceBuffer.size() < MAX_TRACE_SIZE) {
        unw_word_t ip;
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        traceBuffer.push_back(ip);
    }
}

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

struct Module
{
    string fileName;
    uintptr_t baseAddress;
    uint32_t size;
    unsigned int id;
    bool isExe;

    bool operator<(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) < make_tuple(module.baseAddress, module.size, module.fileName);
    }
    bool operator!=(const Module& module) const
    {
        return make_tuple(baseAddress, size, fileName) != make_tuple(module.baseAddress, module.size, module.fileName);
    }
};

struct Data
{
    Data()
    {
        modules.reserve(32);
        ipCache.reserve(65536);
        traceCache.reserve(16384);
        allocationInfo.reserve(16384);

        string outputFileName = env("DUMP_MALLOC_TRACE_OUTPUT") + to_string(getpid());
        out = fopen(outputFileName.c_str(), "wa");
        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        unsetenv("DUMP_MALLOC_TRACE_OUTPUT");
        unsetenv("LD_PRELOAD");
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        fclose(out);
    }

    void updateModuleCache()
    {
        // check list of loaded modules for unknown ones
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        auto& modules = data->modules;
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (modules.empty()) {
                isExe = true;
                ssize_t ret =  readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        uintptr_t addressStart = 0;
        uintptr_t addressEnd = 0;

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                if (addressEnd == 0) {
                    addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                    addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                } else {
                    uintptr_t addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
                    if (addr > addressEnd) {
                        addressEnd = addr;
                    }
                }
            }
        }

        Module module{fileName, addressStart, static_cast<uint32_t>(addressEnd - addressStart), 0, isExe};

        auto it = lower_bound(modules.begin(), modules.end(), module);
        if (it == modules.end() || *it != module) {
            module.id = data->next_module_id++;
            fprintf(data->out, "m %u %s %lx %d\n", module.id, module.fileName.c_str(), module.baseAddress, module.isExe);
            modules.insert(it, module);
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        trace();

        lock_guard<mutex> lock(m_mutex);
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        auto it = traceCache.find(traceBuffer);
        if (it == traceCache.end()) {
            // cache before converting
            auto traceId = next_trace_id++;
            it = traceCache.insert(it, {traceBuffer, traceId});
            // ensure ip cache is up2date
            for (auto& ip : traceBuffer) {
                auto ipIt = ipCache.find(ip);
                if (ipIt == ipCache.end()) {
                    // find module and offset from cache
                    auto module = lower_bound(modules.begin(), modules.end(), ip,
                                                [] (const Module& module, const unw_word_t addr) -> bool {
                                                    return module.baseAddress + module.size < addr;
                                                });
                    if (module == modules.end()) {
                        ip = numeric_limits<unsigned int>::max();
                        continue;
                    }
                    auto ipId = next_ipCache_id++;
                    fprintf(out, "i %u %u %lx\n", ipId, module->id, ip - module->baseAddress);
                    ipIt = ipCache.insert(ipIt, {ip, ipId});
                }
                ip = ipIt->second;
            }
            // print trace
            fprintf(out, "t %u ", traceId);
            for (auto ipId : traceBuffer) {
                if (ipId == numeric_limits<unsigned int>::max()) {
                    continue;
                }
                fprintf(out, "%lu ", ipId);
            }
            fputc('\n', out);
        }
        allocationInfo[ptr] = {size, it->second};
        fprintf(out, "+ %lu %u\n", size, it->second);
    }

    void handleFree(void* ptr)
    {
        lock_guard<mutex> lock(m_mutex);
        auto it = allocationInfo.find(ptr);
        if (it == allocationInfo.end()) {
            return;
        }
        fprintf(out, "- %lu %u\n", it->second.size, it->second.traceId);
        allocationInfo.erase(it);
    }

    mutex m_mutex;
    unsigned int next_module_id = 0;
    unsigned int next_thread_id = 0;
    unsigned int next_ipCache_id = 0;
    unsigned int next_trace_id = 0;

    vector<Module> modules;
    unordered_map<unw_word_t, unw_word_t> ipCache;
    unordered_map<vector<unw_word_t>, unsigned int> traceCache;
    struct AllocationInfo
    {
        size_t size;
        unsigned int traceId;
    };
    unordered_map<void*, AllocationInfo> allocationInfo;
    FILE* out = nullptr;
};

unique_ptr<Data> data;

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    if (data || HandleGuard::inHandler) {
        fprintf(stderr, "initialization recursion detected\n");
        abort();
    }

    HandleGuard guard;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_dlopen = findReal<dlopen_t>("dlopen");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    data.reset(new Data);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    real_free(ptr);

    if (ptr && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
    }
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleFree(ptr);
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2005 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/
#include "mediaobject.h"
#include "mediaobject_p.h"
#include "ifaces/mediaobject.h"
#include "factory.h"

#include <kdebug.h>

namespace Phonon
{
PHONON_HEIR_IMPL( MediaObject, AbstractMediaProducer )

KUrl MediaObject::url() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->url() : d->url;
}

long MediaObject::totalTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->totalTime() : -1;
}

long MediaObject::remainingTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->remainingTime() : -1;
}

long MediaObject::aboutToFinishTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->aboutToFinishTime() : d->aboutToFinishTime;
}

void MediaObject::setUrl( const KUrl& url )
{
	K_D( MediaObject );
	if( iface() )
	{
		d->iface()->setUrl( url );
		if( state() == Phonon::ErrorState )
		{
			d->deleteIface();
			//TODO: at this point MediaObject should try to use an Ifaces::ByteStream
			//instead and send the data it receives from a KIO Job via writeBuffer.
			//This essentially makes all media frameworks read data via KIO...
		}
	}
	else
		d->url = url;
}

void MediaObject::setAboutToFinishTime( long newAboutToFinishTime )
{
	K_D( MediaObject );
	//kDebug( 600 ) << k_funcinfo << endl;
	if( d->iface() )
		d->iface()->setAboutToFinishTime( newAboutToFinishTime );
	else
		d->aboutToFinishTime = newAboutToFinishTime;
}

bool MediaObjectPrivate::aboutToDeleteIface()
{
	//kDebug( 600 ) << k_funcinfo << endl;
	if( iface() )
		aboutToFinishTime = iface()->aboutToFinishTime();
	return AbstractMediaProducerPrivate::aboutToDeleteIface();
}

void MediaObject::setupIface()
{
	K_D( MediaObject );
	Q_ASSERT( d->iface() );
	//kDebug( 600 ) << k_funcinfo << endl;
	AbstractMediaProducer::setupIface();

	connect( d->iface()->qobject(), SIGNAL( finished() ), SIGNAL( finished() ) );
	connect( d->iface()->qobject(), SIGNAL( aboutToFinish( long ) ), SIGNAL( aboutToFinish( long ) ) );
	connect( d->iface()->qobject(), SIGNAL( length( long ) ), SIGNAL( length( long ) ) );

	// set up attributes
	if( !d->url.isEmpty() )
		d->iface()->setUrl( d->url );
	if( state() == Phonon::ErrorState )
	{
		d->deleteIface();
		//TODO: at this point MediaObject should try to use an Ifaces::ByteStream
		//instead and send the data it receives from a KIO Job via writeBuffer.
		//This essentially makes all media frameworks read data via KIO...
		return;
	}
	d->iface()->setAboutToFinishTime( d->aboutToFinishTime );
}

} //namespace Phonon

#include "mediaobject.moc"

// vim: sw=4 ts=4 tw=80 noet
<commit_msg>SVN_SILENT: call stop before setUrl on the iface object<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2005 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/
#include "mediaobject.h"
#include "mediaobject_p.h"
#include "ifaces/mediaobject.h"
#include "factory.h"

#include <kdebug.h>

namespace Phonon
{
PHONON_HEIR_IMPL( MediaObject, AbstractMediaProducer )

KUrl MediaObject::url() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->url() : d->url;
}

long MediaObject::totalTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->totalTime() : -1;
}

long MediaObject::remainingTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->remainingTime() : -1;
}

long MediaObject::aboutToFinishTime() const
{
	K_D( const MediaObject );
	return d->iface() ? d->iface()->aboutToFinishTime() : d->aboutToFinishTime;
}

void MediaObject::setUrl( const KUrl& url )
{
	K_D( MediaObject );
	if( iface() )
	{
		d->iface()->stop(); // first call stop as that often is the expected state
		                    // for setting a new URL
		d->iface()->setUrl( url );
		if( state() == Phonon::ErrorState )
		{
			d->deleteIface();
			//TODO: at this point MediaObject should try to use an Ifaces::ByteStream
			//instead and send the data it receives from a KIO Job via writeBuffer.
			//This essentially makes all media frameworks read data via KIO...
		}
	}
	else
		d->url = url;
}

void MediaObject::setAboutToFinishTime( long newAboutToFinishTime )
{
	K_D( MediaObject );
	//kDebug( 600 ) << k_funcinfo << endl;
	if( d->iface() )
		d->iface()->setAboutToFinishTime( newAboutToFinishTime );
	else
		d->aboutToFinishTime = newAboutToFinishTime;
}

bool MediaObjectPrivate::aboutToDeleteIface()
{
	//kDebug( 600 ) << k_funcinfo << endl;
	if( iface() )
		aboutToFinishTime = iface()->aboutToFinishTime();
	return AbstractMediaProducerPrivate::aboutToDeleteIface();
}

void MediaObject::setupIface()
{
	K_D( MediaObject );
	Q_ASSERT( d->iface() );
	//kDebug( 600 ) << k_funcinfo << endl;
	AbstractMediaProducer::setupIface();

	connect( d->iface()->qobject(), SIGNAL( finished() ), SIGNAL( finished() ) );
	connect( d->iface()->qobject(), SIGNAL( aboutToFinish( long ) ), SIGNAL( aboutToFinish( long ) ) );
	connect( d->iface()->qobject(), SIGNAL( length( long ) ), SIGNAL( length( long ) ) );

	// set up attributes
	if( !d->url.isEmpty() )
		d->iface()->setUrl( d->url );
	if( state() == Phonon::ErrorState )
	{
		d->deleteIface();
		//TODO: at this point MediaObject should try to use an Ifaces::ByteStream
		//instead and send the data it receives from a KIO Job via writeBuffer.
		//This essentially makes all media frameworks read data via KIO...
		return;
	}
	d->iface()->setAboutToFinishTime( d->aboutToFinishTime );
}

} //namespace Phonon

#include "mediaobject.moc"

// vim: sw=4 ts=4 tw=80 noet
<|endoftext|>


<commit_before>#include "type_traits.h"
#include <type_traits>

// In each test, replace XXX with syntax that passes the test.

BOOST_AUTO_TEST_CASE(is_void)
{
    BOOST_REQUIRE_EQUAL(true, std::is_void<XXX>::value);
    std::is_void<XXX> val;
    BOOST_REQUIRE_EQUAL(true, static_cast<bool>(val));
}

BOOST_AUTO_TEST_CASE(is_integral)
{
    BOOST_REQUIRE_EQUAL(true, std::is_integral<XXX>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype('!')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(false)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(666ULL)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(0.)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(0.f)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(L'!')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(L"Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(R"(Hello, "world"!)")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<const int>::value);
}

BOOST_AUTO_TEST_CASE(is_floating_point)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<float>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<long double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0 + 1.)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0. + 1)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0 + 1)>::value);
}

BOOST_AUTO_TEST_CASE(is_array)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int>::value);
    typedef std::array<int, 10> std_array;
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<std_array>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int &>::value);
    BOOST_REQUIRE_EQUAL(true, std::is_array<XXX>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int *[10]>::value);
}

BOOST_AUTO_TEST_CASE(is_enum)
{
    BOOST_REQUIRE_EQUAL(true, std::is_enum<XXX>::value);
}

BOOST_AUTO_TEST_CASE(is_union)
{
    BOOST_REQUIRE_EQUAL(true, std::is_union<XXX>::value);
    struct S {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_union<S>::value);
}

BOOST_AUTO_TEST_CASE(is_class)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<int>::value);
    struct S {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<S>::value);
    class C {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<C>::value);
    union U {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<U>::value);
    typedef int A[10];
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<A>::value);
}

BOOST_AUTO_TEST_CASE(is_function)
{
    struct S {};
    S s1();
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<decltype(s1)>::value);
    S s2{};
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<decltype(s2)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<void()>::value);
    typedef void p();
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<p>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<p *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<std::function<void()>>::value);
}

BOOST_AUTO_TEST_CASE(is_pointer)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<void>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<void *>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype(&i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype('&')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype("Hello, world!" + 1)>::value);
}

BOOST_AUTO_TEST_CASE(is_lvalue_reference)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int &&>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<decltype(&i)>::value);
}

BOOST_AUTO_TEST_CASE(is_rvalue_reference)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int &&>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<decltype(&i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<decltype(std::move(i))>::value);
}

BOOST_AUTO_TEST_CASE(is_member_object_pointer)
{
    struct S { int i; };
    S s;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&s)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&S::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<int(S::*)>::value);
    union U { int i; char c; };
    U u;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&u)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&U::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<int(U::*)>::value);
}

BOOST_AUTO_TEST_CASE(is_member_function_pointer)
{
    struct S { char c; void i() {} };
    S s;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&s)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&S::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&S::c)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<void(S::*)()>::value);
}

BOOST_AUTO_TEST_CASE(is_arithmetic)
{
    BOOST_REQUIRE_EQUAL(false, std::is_arithmetic<void>::value);
    BOOST_REQUIRE_EQUAL(false, std::is_arithmetic<std::nullptr_t>::value);
    BOOST_REQUIRE_EQUAL(std::is_integral<XXX>::value, std::is_arithmetic<bool>::value);
    BOOST_REQUIRE_EQUAL(std::is_floating_point<XXX>::value, std::is_arithmetic<float>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char16_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char32_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<wchar_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<unsigned char>::value);
    BOOST_REQUIRE_EQUAL(true, std::is_arithmetic<std::vector<XXX>::value_type>::value);
}

BOOST_AUTO_TEST_CASE(is_fundamental)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<void>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::nullptr_t>::value);
    BOOST_REQUIRE_EQUAL(std::is_arithmetic<XXX>::value, std::is_fundamental<bool>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<unsigned char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::string>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<decltype("Hello, world!" + 1)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int *>>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int> *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int>::value_type>::value);
}

BOOST_AUTO_TEST_CASE(is_const)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<const int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<const int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int *const>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const *const>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const &>::value);
}

BOOST_AUTO_TEST_CASE(is_volatile)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<volatile int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<volatile int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int *volatile>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile *volatile>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile &>::value);
}
<commit_msg>std::is_trivial<T><commit_after>#include "type_traits.h"
#include <type_traits>

// In each test, replace XXX with syntax that passes the test.

BOOST_AUTO_TEST_CASE(is_void)
{
    BOOST_REQUIRE_EQUAL(true, std::is_void<XXX>::value);
    std::is_void<XXX> val;
    BOOST_REQUIRE_EQUAL(true, static_cast<bool>(val));
}

BOOST_AUTO_TEST_CASE(is_integral)
{
    BOOST_REQUIRE_EQUAL(true, std::is_integral<XXX>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype('!')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(false)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(666ULL)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(0.)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(0.f)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(L'!')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(L"Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<decltype(R"(Hello, "world"!)")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_integral<const int>::value);
}

BOOST_AUTO_TEST_CASE(is_floating_point)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<float>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<long double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0 + 1.)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0. + 1)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_floating_point<decltype(0 + 1)>::value);
}

BOOST_AUTO_TEST_CASE(is_array)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int>::value);
    typedef std::array<int, 10> std_array;
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<std_array>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int &>::value);
    BOOST_REQUIRE_EQUAL(true, std::is_array<XXX>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_array<int *[10]>::value);
}

BOOST_AUTO_TEST_CASE(is_enum)
{
    BOOST_REQUIRE_EQUAL(true, std::is_enum<XXX>::value);
}

BOOST_AUTO_TEST_CASE(is_union)
{
    BOOST_REQUIRE_EQUAL(true, std::is_union<XXX>::value);
    struct S {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_union<S>::value);
}

BOOST_AUTO_TEST_CASE(is_class)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<int>::value);
    struct S {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<S>::value);
    class C {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<C>::value);
    union U {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<U>::value);
    typedef int A[10];
    BOOST_REQUIRE_EQUAL(xxx, std::is_class<A>::value);
}

BOOST_AUTO_TEST_CASE(is_function)
{
    struct S {};
    S s1();
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<decltype(s1)>::value);
    S s2{};
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<decltype(s2)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<void()>::value);
    typedef void p();
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<p>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<p *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_function<std::function<void()>>::value);
}

BOOST_AUTO_TEST_CASE(is_pointer)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<void>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<void *>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype(&i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype('&')>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_pointer<decltype("Hello, world!" + 1)>::value);
}

BOOST_AUTO_TEST_CASE(is_lvalue_reference)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<int &&>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_lvalue_reference<decltype(&i)>::value);
}

BOOST_AUTO_TEST_CASE(is_rvalue_reference)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int &>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<int &&>::value);
    int i;
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<decltype(&i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_rvalue_reference<decltype(std::move(i))>::value);
}

BOOST_AUTO_TEST_CASE(is_member_object_pointer)
{
    struct S { int i; };
    S s;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&s)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&S::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<int(S::*)>::value);
    union U { int i; char c; };
    U u;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&u)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<decltype(&U::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_object_pointer<int(U::*)>::value);
}

BOOST_AUTO_TEST_CASE(is_member_function_pointer)
{
    struct S { char c; void i() {} };
    S s;
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&s)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&S::i)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<decltype(&S::c)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_member_function_pointer<void(S::*)()>::value);
}

BOOST_AUTO_TEST_CASE(is_arithmetic)
{
    BOOST_REQUIRE_EQUAL(false, std::is_arithmetic<void>::value);
    BOOST_REQUIRE_EQUAL(false, std::is_arithmetic<std::nullptr_t>::value);
    BOOST_REQUIRE_EQUAL(std::is_integral<XXX>::value, std::is_arithmetic<bool>::value);
    BOOST_REQUIRE_EQUAL(std::is_floating_point<XXX>::value, std::is_arithmetic<float>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char16_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<char32_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<wchar_t>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_arithmetic<unsigned char>::value);
    BOOST_REQUIRE_EQUAL(true, std::is_arithmetic<std::vector<XXX>::value_type>::value);
}

BOOST_AUTO_TEST_CASE(is_fundamental)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<void>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::nullptr_t>::value);
    BOOST_REQUIRE_EQUAL(std::is_arithmetic<XXX>::value, std::is_fundamental<bool>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<unsigned char>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<double>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::string>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<decltype("Hello, world!")>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<decltype("Hello, world!" + 1)>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int *>>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int> *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_fundamental<std::vector<int>::value_type>::value);
}

BOOST_AUTO_TEST_CASE(is_const)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<const int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<const int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int *const>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const *const>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_const<int const &>::value);
}

BOOST_AUTO_TEST_CASE(is_volatile)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<volatile int>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<volatile int *>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int *volatile>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile *volatile>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_volatile<int volatile &>::value);
}

BOOST_AUTO_TEST_CASE(is_trivial)
{
    BOOST_REQUIRE_EQUAL(xxx, std::is_trivial<int>::value);
    class Empty {};
    BOOST_REQUIRE_EQUAL(xxx, std::is_trivial<Empty>::value);
    BOOST_REQUIRE_EQUAL(xxx, std::is_trivial<Empty[10]>::value);
    class CustomConstructor
    {
    public:
        CustomConstructor(int i) : i_(i) {}
    private:
        int &i_;
    };
    BOOST_REQUIRE_EQUAL(xxx, std::is_trivial<CustomConstructor>::value);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string>

#include <ori/oriutil.h>

#include "fuse_cmd.h"

bool OF_HasFuse()
{
    return OF_ControlPath() != "";
}

std::string OF_ControlPath()
{
    char *cwdbuf = getcwd(NULL, 0);
    std::string path = cwdbuf;
    free(cwdbuf);

    while (path.size() > 0) {
        std::string control_path = path + "/" + ORI_CONTROL_FILENAME;
        if (Util_FileExists(control_path)) {
            return control_path;
        }
        path = StrUtil_Dirname(path);
    }

    return "";
}

bool OF_RunCommand(const char *cmd)
{
    std::string controlPath = OF_ControlPath();
    if (controlPath.size() == 0)
        return false;

    int fd = open(controlPath.c_str(), O_RDWR | O_TRUNC);
    if (fd < 0) {
        perror("OF_RunCommand open");
        return false;
    }

    write(fd, cmd, strlen(cmd));
    fsync(fd);
    lseek(fd, 0, SEEK_SET);

    // Read output
    struct stat sb;
    fstat(fd, &sb);
    size_t left = sb.st_size;
    while (left > 0) {
        size_t to_read = left;
        if (to_read > 1024)
            to_read = 1024;

        char buf[1024];
        read(fd, buf, to_read);
        fwrite(buf, to_read, 1, stdout);
        left -= to_read;
    }

    return true;
}

<commit_msg>Handle read/write errors in the CLI-FUSE control interface more gracefully.<commit_after>/*
 * Copyright (c) 2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

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

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string>

#include <ori/oriutil.h>

#include "fuse_cmd.h"

bool OF_HasFuse()
{
    return OF_ControlPath() != "";
}

std::string OF_ControlPath()
{
    char *cwdbuf = getcwd(NULL, 0);
    std::string path = cwdbuf;
    free(cwdbuf);

    while (path.size() > 0) {
        std::string control_path = path + "/" + ORI_CONTROL_FILENAME;
        if (Util_FileExists(control_path)) {
            return control_path;
        }
        path = StrUtil_Dirname(path);
    }

    return "";
}

bool OF_RunCommand(const char *cmd)
{
    size_t status;
    std::string controlPath = OF_ControlPath();

    if (controlPath.size() == 0)
        return false;

    int fd = open(controlPath.c_str(), O_RDWR | O_TRUNC);
    if (fd < 0) {
        perror("OF_RunCommand open");
        return false;
    }

    status = write(fd, cmd, strlen(cmd));
    if (status < 0) {
        perror("Failed to write control node");
        return false;
    }
    fsync(fd);
    lseek(fd, 0, SEEK_SET);

    // Read output
    struct stat sb;
    fstat(fd, &sb);
    size_t left = sb.st_size;
    while (left > 0) {
        size_t to_read = left;
        if (to_read > 1024)
            to_read = 1024;

        char buf[1024];
        int bytes_read = read(fd, buf, to_read);
        if (bytes_read == -1) {
            perror("Failed to read control node");
            return false;
        }
        fwrite(buf, bytes_read, 1, stdout);
        left -= bytes_read;
    }

    return true;
}

<|endoftext|>