<commit_before>#include <build-bot/bot.h>

#include <sys/types.h>
#include <sys/stat.h>

#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

namespace fs = boost::filesystem;
using namespace dsn::build_bot;

namespace dsn {
namespace build_bot {
    namespace priv {
        class Bot : public dsn::log::Base<Bot> {
        protected:
            boost::property_tree::ptree m_settings;

            bool loadConfig(const std::string& config_file)
            {
                BOOST_LOG_SEV(log, severity::info) << "Loading configuration from " << config_file;

                fs::path path(config_file);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " doesn't exist!";
                    return false;
                }

                if (!fs::is_regular_file(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " isn't a regular file!";
                    return false;
                }

                try {
                    boost::property_tree::read_ini(config_file, m_settings);
                }

                catch (boost::property_tree::ini_parser_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to parse config file " << config_file << ": " << ex.what();
                    return false;
                }

                return true;
            }

            bool initFifo()
            {
                std::string fifoName;
                try {
                    fifoName = m_settings.get<std::string>("fifo.name");
                }

                catch (boost::property_tree::ptree_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to get FIFO settings from configuration: " << ex.what();
                    return false;
                }

                fs::path path(fifoName);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::warning) << "FIFO " << fifoName << " doesn't exist; trying to create it!";
                    if (mkfifo(fifoName.c_str(), 0666) == -1) {
                        BOOST_LOG_SEV(log, severity::error) << "Failed to create FIFO " << fifoName << ": " << strerror(errno);
                        return false;
                    }
                }

                return true;
            }

        public:
            bool init(const std::string& config_file)
            {
                if (!loadConfig(config_file))
                    return false;

                if (!initFifo())
                    return false;

                return true;
            }
        };
    }
}
}

const std::string dsn::build_bot::Bot::DEFAULT_CONFIG_FILE{ "etc/build-bot/bot.conf" };

Bot::Bot()
    : m_impl(new priv::Bot())
{
}

Bot::~Bot()
{
}

bool Bot::init(const std::string& config_file)
{
    return m_impl->init(config_file);
}
<commit_msg>Add boost::asio::io_service to Bot<commit_after>#include <build-bot/bot.h>

#include <sys/types.h>
#include <sys/stat.h>

#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

namespace fs = boost::filesystem;
using namespace dsn::build_bot;

namespace dsn {
namespace build_bot {
    namespace priv {
        class Bot : public dsn::log::Base<Bot> {
        protected:
            boost::property_tree::ptree m_settings;

            bool loadConfig(const std::string& config_file)
            {
                BOOST_LOG_SEV(log, severity::info) << "Loading configuration from " << config_file;

                fs::path path(config_file);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " doesn't exist!";
                    return false;
                }

                if (!fs::is_regular_file(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " isn't a regular file!";
                    return false;
                }

                try {
                    boost::property_tree::read_ini(config_file, m_settings);
                }

                catch (boost::property_tree::ini_parser_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to parse config file " << config_file << ": " << ex.what();
                    return false;
                }

                return true;
            }

            bool initFifo()
            {
                std::string fifoName;
                try {
                    fifoName = m_settings.get<std::string>("fifo.name");
                }

                catch (boost::property_tree::ptree_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to get FIFO settings from configuration: " << ex.what();
                    return false;
                }

                fs::path path(fifoName);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::warning) << "FIFO " << fifoName << " doesn't exist; trying to create it!";
                    if (mkfifo(fifoName.c_str(), 0666) == -1) {
                        BOOST_LOG_SEV(log, severity::error) << "Failed to create FIFO " << fifoName << ": " << strerror(errno);
                        return false;
                    }
                }

                return true;
            }

            boost::asio::io_service m_io;
            boost::asio::strand m_strand;

        public:
            Bot()
                : m_io()
                , m_strand(m_io)
            {
            }

            bool init(const std::string& config_file)
            {
                if (!loadConfig(config_file))
                    return false;

                if (!initFifo())
                    return false;

                return true;
            }
        };
    }
}
}

const std::string dsn::build_bot::Bot::DEFAULT_CONFIG_FILE{ "etc/build-bot/bot.conf" };

Bot::Bot()
    : m_impl(new priv::Bot())
{
}

Bot::~Bot()
{
}

bool Bot::init(const std::string& config_file)
{
    return m_impl->init(config_file);
}
<|endoftext|>


<commit_before>//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Live Variables analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Basic/SourceManager.h"
#include "clang/AST/Expr.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"

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

using namespace clang;

//===----------------------------------------------------------------------===//
// Useful constants.
//===----------------------------------------------------------------------===//

static const bool Alive = true;
static const bool Dead = false;

//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//

namespace {
class VISIBILITY_HIDDEN RegisterDecls
  : public CFGRecStmtDeclVisitor<RegisterDecls> {

  LiveVariables::AnalysisDataTy& AD;

  typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy;
  AlwaysLiveTy AlwaysLive;

public:
  RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}

  ~RegisterDecls() {

    AD.AlwaysLive.resetValues(AD);

    for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end();
         I != E; ++ I)
      AD.AlwaysLive(*I, AD) = Alive;
  }

  void VisitImplicitParamDecl(ImplicitParamDecl* IPD) {
    // Register the VarDecl for tracking.
    AD.Register(IPD);
  }

  void VisitVarDecl(VarDecl* VD) {
    // Register the VarDecl for tracking.
    AD.Register(VD);

    // Does the variable have global storage?  If so, it is always live.
    if (VD->hasGlobalStorage())
      AlwaysLive.push_back(VD);
  }

  void VisitUnaryOperator(UnaryOperator* U) {
    // Check for '&'.  Any VarDecl whose value has its address-taken we
    // treat as always being live (flow-insensitive).

    Expr* E = U->getSubExpr()->IgnoreParenCasts();

    if (U->getOpcode() == UnaryOperator::AddrOf)
      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
        if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
          AD.Register(VD);
          AlwaysLive.push_back(VD);
          return;
        }

    Visit(E);
  }

  CFG& getCFG() { return AD.getCFG(); }
};
} // end anonymous namespace

LiveVariables::LiveVariables(CFG& cfg) {
  // Register all referenced VarDecls.
  getAnalysisData().setCFG(&cfg);
  RegisterDecls R(getAnalysisData());
  cfg.VisitBlockStmts(R);
}

//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
  LiveVariables::AnalysisDataTy& AD;
  LiveVariables::ValTy LiveState;
public:
  TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}

  LiveVariables::ValTy& getVal() { return LiveState; }
  CFG& getCFG() { return AD.getCFG(); }

  void VisitDeclRefExpr(DeclRefExpr* DR);
  void VisitBinaryOperator(BinaryOperator* B);
  void VisitAssign(BinaryOperator* B);
  void VisitDeclStmt(DeclStmt* DS);
  void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
  void VisitUnaryOperator(UnaryOperator* U);
  void Visit(Stmt *S);
  void VisitTerminator(CFGBlock* B);

  void SetTopValue(LiveVariables::ValTy& V) {
    V = AD.AlwaysLive;
  }

};

void TransferFuncs::Visit(Stmt *S) {

  if (S == getCurrentBlkStmt()) {

    if (AD.Observer)
      AD.Observer->ObserveStmt(S,AD,LiveState);

    if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
    StmtVisitor<TransferFuncs,void>::Visit(S);
  }
  else if (!getCFG().isBlkExpr(S)) {

    if (AD.Observer)
      AD.Observer->ObserveStmt(S,AD,LiveState);

    StmtVisitor<TransferFuncs,void>::Visit(S);

  }
  else
    // For block-level expressions, mark that they are live.
    LiveState(S,AD) = Alive;
}

void TransferFuncs::VisitTerminator(CFGBlock* B) {

  const Stmt* E = B->getTerminatorCondition();

  if (!E)
    return;

  assert (getCFG().isBlkExpr(E));
  LiveState(E, AD) = Alive;
}

void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
  if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
    LiveState(V,AD) = Alive;
}

void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
  if (B->isAssignmentOp()) VisitAssign(B);
  else VisitStmt(B);
}

void
TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {

  // This represents a 'use' of the collection.
  Visit(S->getCollection());

  // This represents a 'kill' for the variable.
  Stmt* Element = S->getElement();
  DeclRefExpr *DR = 0;
  VarDecl* VD = 0;

  if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
    VD = cast<VarDecl>(DS->getSolitaryDecl());
  else {
    DR = cast<DeclRefExpr>(Element);
    VD = cast<VarDecl>(DR->getDecl());
  }

  LiveState(VD, AD) = Dead;
  if (AD.Observer && DR) { AD.Observer->ObserverKill(DR); }
}

void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
  Expr *E = U->getSubExpr();

  switch (U->getOpcode()) {
  case UnaryOperator::PostInc:
  case UnaryOperator::PostDec:
  case UnaryOperator::PreInc:
  case UnaryOperator::PreDec:
    // Walk through the subexpressions, blasting through ParenExprs
    // until we either find a DeclRefExpr or some non-DeclRefExpr
    // expression.
    if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
      if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
        // Treat the --/++ operator as a kill.
        if (AD.Observer) { AD.Observer->ObserverKill(DR); }
        LiveState(VD, AD) = Alive;
        return VisitDeclRefExpr(DR);
      }

    // Fall-through.

  default:
    return Visit(E);
  }
}

void TransferFuncs::VisitAssign(BinaryOperator* B) {
  Expr* LHS = B->getLHS();

  // Assigning to a variable?
  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {

    // Update liveness inforamtion.
    unsigned bit = AD.getIdx(DR->getDecl());
    LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);

    if (AD.Observer) { AD.Observer->ObserverKill(DR); }

    // Handle things like +=, etc., which also generate "uses"
    // of a variable.  Do this just by visiting the subexpression.
    if (B->getOpcode() != BinaryOperator::Assign)
      VisitDeclRefExpr(DR);
  }
  else // Not assigning to a variable.  Process LHS as usual.
    Visit(LHS);

  Visit(B->getRHS());
}

void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
  // Declarations effectively "kill" a variable since they cannot
  // possibly be live before they are declared.
  for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
       DI != DE; ++DI)
    if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) {
      // The initializer is evaluated after the variable comes into scope.
      // Since this is a reverse dataflow analysis, we must evaluate the
      // transfer function for this expression first.
      if (Expr* Init = VD->getInit())
        Visit(Init);

      // Update liveness information by killing the VarDecl.
      unsigned bit = AD.getIdx(VD);
      LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
    }
}

} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Merge operator: if something is live on any successor block, it is live
//  in the current block (a set union).
//===----------------------------------------------------------------------===//

namespace {

struct Merge {
  typedef StmtDeclBitVector_Types::ValTy ValTy;

  void operator()(ValTy& Dst, const ValTy& Src) {
    Dst.OrDeclBits(Src);
    Dst.AndBlkExprBits(Src);
  }
};

typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// External interface to run Liveness analysis.
//===----------------------------------------------------------------------===//

void LiveVariables::runOnCFG(CFG& cfg) {
  Solver S(*this);
  S.runOnCFG(cfg);
}

void LiveVariables::runOnAllBlocks(const CFG& cfg,
                                   LiveVariables::ObserverTy* Obs,
                                   bool recordStmtValues) {
  Solver S(*this);
  ObserverTy* OldObserver = getAnalysisData().Observer;
  getAnalysisData().Observer = Obs;
  S.runOnAllBlocks(cfg, recordStmtValues);
  getAnalysisData().Observer = OldObserver;
}

//===----------------------------------------------------------------------===//
// liveness queries
//

bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
  DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
  return i.isValid() ? getBlockData(B).getBit(i) : false;
}

bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
  DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
  return i.isValid() ? Live.getBit(i) : false;
}

bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
  return getStmtData(Loc)(StmtVal,getAnalysisData());
}

bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
  return getStmtData(Loc)(D,getAnalysisData());
}

//===----------------------------------------------------------------------===//
// printing liveness state for debugging
//

void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
  const AnalysisDataTy& AD = getAnalysisData();

  for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
                                     E = AD.end_decl(); I!=E; ++I)
    if (V.getDeclBit(I->second)) {
      SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());

      fprintf(stderr, "  %s <%s:%u:%u>\n",
              I->first->getIdentifier()->getName(),
              SM.getSourceName(PhysLoc),
              SM.getLineNumber(PhysLoc),
              SM.getColumnNumber(PhysLoc));
    }
}

void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
  for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
       E = getBlockDataMap().end(); I!=E; ++I) {
    fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
            I->first->getBlockID());

    dumpLiveness(I->second,M);
  }

  fprintf(stderr,"\n");
}
<commit_msg>Handle the case where 'element' in ObjCforCollectionstmt is not a DeclStmt or DeclRefExpr.<commit_after>//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Live Variables analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Basic/SourceManager.h"
#include "clang/AST/Expr.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"

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

using namespace clang;

//===----------------------------------------------------------------------===//
// Useful constants.
//===----------------------------------------------------------------------===//

static const bool Alive = true;
static const bool Dead = false;

//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//

namespace {
class VISIBILITY_HIDDEN RegisterDecls
  : public CFGRecStmtDeclVisitor<RegisterDecls> {

  LiveVariables::AnalysisDataTy& AD;

  typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy;
  AlwaysLiveTy AlwaysLive;

public:
  RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}

  ~RegisterDecls() {

    AD.AlwaysLive.resetValues(AD);

    for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end();
         I != E; ++ I)
      AD.AlwaysLive(*I, AD) = Alive;
  }

  void VisitImplicitParamDecl(ImplicitParamDecl* IPD) {
    // Register the VarDecl for tracking.
    AD.Register(IPD);
  }

  void VisitVarDecl(VarDecl* VD) {
    // Register the VarDecl for tracking.
    AD.Register(VD);

    // Does the variable have global storage?  If so, it is always live.
    if (VD->hasGlobalStorage())
      AlwaysLive.push_back(VD);
  }

  void VisitUnaryOperator(UnaryOperator* U) {
    // Check for '&'.  Any VarDecl whose value has its address-taken we
    // treat as always being live (flow-insensitive).

    Expr* E = U->getSubExpr()->IgnoreParenCasts();

    if (U->getOpcode() == UnaryOperator::AddrOf)
      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
        if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
          AD.Register(VD);
          AlwaysLive.push_back(VD);
          return;
        }

    Visit(E);
  }

  CFG& getCFG() { return AD.getCFG(); }
};
} // end anonymous namespace

LiveVariables::LiveVariables(CFG& cfg) {
  // Register all referenced VarDecls.
  getAnalysisData().setCFG(&cfg);
  RegisterDecls R(getAnalysisData());
  cfg.VisitBlockStmts(R);
}

//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//

namespace {

class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
  LiveVariables::AnalysisDataTy& AD;
  LiveVariables::ValTy LiveState;
public:
  TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}

  LiveVariables::ValTy& getVal() { return LiveState; }
  CFG& getCFG() { return AD.getCFG(); }

  void VisitDeclRefExpr(DeclRefExpr* DR);
  void VisitBinaryOperator(BinaryOperator* B);
  void VisitAssign(BinaryOperator* B);
  void VisitDeclStmt(DeclStmt* DS);
  void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
  void VisitUnaryOperator(UnaryOperator* U);
  void Visit(Stmt *S);
  void VisitTerminator(CFGBlock* B);

  void SetTopValue(LiveVariables::ValTy& V) {
    V = AD.AlwaysLive;
  }

};

void TransferFuncs::Visit(Stmt *S) {

  if (S == getCurrentBlkStmt()) {

    if (AD.Observer)
      AD.Observer->ObserveStmt(S,AD,LiveState);

    if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
    StmtVisitor<TransferFuncs,void>::Visit(S);
  }
  else if (!getCFG().isBlkExpr(S)) {

    if (AD.Observer)
      AD.Observer->ObserveStmt(S,AD,LiveState);

    StmtVisitor<TransferFuncs,void>::Visit(S);

  }
  else
    // For block-level expressions, mark that they are live.
    LiveState(S,AD) = Alive;
}

void TransferFuncs::VisitTerminator(CFGBlock* B) {

  const Stmt* E = B->getTerminatorCondition();

  if (!E)
    return;

  assert (getCFG().isBlkExpr(E));
  LiveState(E, AD) = Alive;
}

void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
  if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
    LiveState(V,AD) = Alive;
}

void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
  if (B->isAssignmentOp()) VisitAssign(B);
  else VisitStmt(B);
}

void
TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {

  // This represents a 'use' of the collection.
  Visit(S->getCollection());

  // This represents a 'kill' for the variable.
  Stmt* Element = S->getElement();
  DeclRefExpr* DR = 0;
  VarDecl* VD = 0;

  if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
    VD = cast<VarDecl>(DS->getSolitaryDecl());
  else {
    Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
    if ((DR = dyn_cast<DeclRefExpr>(ElemExpr)))
      VD = cast<VarDecl>(DR->getDecl());
  }

  if (VD) {
    LiveState(VD, AD) = Dead;
    if (AD.Observer && DR) { AD.Observer->ObserverKill(DR); }
  }
}

void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
  Expr *E = U->getSubExpr();

  switch (U->getOpcode()) {
  case UnaryOperator::PostInc:
  case UnaryOperator::PostDec:
  case UnaryOperator::PreInc:
  case UnaryOperator::PreDec:
    // Walk through the subexpressions, blasting through ParenExprs
    // until we either find a DeclRefExpr or some non-DeclRefExpr
    // expression.
    if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
      if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
        // Treat the --/++ operator as a kill.
        if (AD.Observer) { AD.Observer->ObserverKill(DR); }
        LiveState(VD, AD) = Alive;
        return VisitDeclRefExpr(DR);
      }

    // Fall-through.

  default:
    return Visit(E);
  }
}

void TransferFuncs::VisitAssign(BinaryOperator* B) {
  Expr* LHS = B->getLHS();

  // Assigning to a variable?
  if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {

    // Update liveness inforamtion.
    unsigned bit = AD.getIdx(DR->getDecl());
    LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);

    if (AD.Observer) { AD.Observer->ObserverKill(DR); }

    // Handle things like +=, etc., which also generate "uses"
    // of a variable.  Do this just by visiting the subexpression.
    if (B->getOpcode() != BinaryOperator::Assign)
      VisitDeclRefExpr(DR);
  }
  else // Not assigning to a variable.  Process LHS as usual.
    Visit(LHS);

  Visit(B->getRHS());
}

void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
  // Declarations effectively "kill" a variable since they cannot
  // possibly be live before they are declared.
  for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
       DI != DE; ++DI)
    if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) {
      // The initializer is evaluated after the variable comes into scope.
      // Since this is a reverse dataflow analysis, we must evaluate the
      // transfer function for this expression first.
      if (Expr* Init = VD->getInit())
        Visit(Init);

      // Update liveness information by killing the VarDecl.
      unsigned bit = AD.getIdx(VD);
      LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
    }
}

} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Merge operator: if something is live on any successor block, it is live
//  in the current block (a set union).
//===----------------------------------------------------------------------===//

namespace {

struct Merge {
  typedef StmtDeclBitVector_Types::ValTy ValTy;

  void operator()(ValTy& Dst, const ValTy& Src) {
    Dst.OrDeclBits(Src);
    Dst.AndBlkExprBits(Src);
  }
};

typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// External interface to run Liveness analysis.
//===----------------------------------------------------------------------===//

void LiveVariables::runOnCFG(CFG& cfg) {
  Solver S(*this);
  S.runOnCFG(cfg);
}

void LiveVariables::runOnAllBlocks(const CFG& cfg,
                                   LiveVariables::ObserverTy* Obs,
                                   bool recordStmtValues) {
  Solver S(*this);
  ObserverTy* OldObserver = getAnalysisData().Observer;
  getAnalysisData().Observer = Obs;
  S.runOnAllBlocks(cfg, recordStmtValues);
  getAnalysisData().Observer = OldObserver;
}

//===----------------------------------------------------------------------===//
// liveness queries
//

bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
  DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
  return i.isValid() ? getBlockData(B).getBit(i) : false;
}

bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
  DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
  return i.isValid() ? Live.getBit(i) : false;
}

bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
  return getStmtData(Loc)(StmtVal,getAnalysisData());
}

bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
  return getStmtData(Loc)(D,getAnalysisData());
}

//===----------------------------------------------------------------------===//
// printing liveness state for debugging
//

void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
  const AnalysisDataTy& AD = getAnalysisData();

  for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
                                     E = AD.end_decl(); I!=E; ++I)
    if (V.getDeclBit(I->second)) {
      SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());

      fprintf(stderr, "  %s <%s:%u:%u>\n",
              I->first->getIdentifier()->getName(),
              SM.getSourceName(PhysLoc),
              SM.getLineNumber(PhysLoc),
              SM.getColumnNumber(PhysLoc));
    }
}

void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
  for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
       E = getBlockDataMap().end(); I!=E; ++I) {
    fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
            I->first->getBlockID());

    dumpLiveness(I->second,M);
  }

  fprintf(stderr,"\n");
}
<|endoftext|>


<commit_before>#include "playlistcontainermodel.h"

namespace sp = Spotinetta;

namespace Sonetta {

PlaylistContainerModel::PlaylistContainerModel(const Spotinetta::Session *session, QObject *parent)
    :   QAbstractListModel(parent), m_session(session)
{
    m_watcher = new sp::PlaylistContainerWatcher(session, this);

    connect(m_watcher, &sp::PlaylistContainerWatcher::loaded,
            this, &PlaylistContainerModel::onLoaded);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistAdded,
            this, &PlaylistContainerModel::onPlaylistAdded);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistMoved,
            this, &PlaylistContainerModel::onPlaylistMoved);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistRemoved,
            this, &PlaylistContainerModel::onPlaylistRemoved);

    m_stateChangedMapper = new QSignalMapper(this);
    m_renamedMapper = new QSignalMapper(this);
    m_imageChangedMapper = new QSignalMapper(this);
    m_descriptionChangedMapper = new QSignalMapper(this);

    connect(m_stateChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistStateChanged(int)));
    connect(m_renamedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistRenamed(int)));
    connect(m_imageChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistImageChanged(int)));
    connect(m_descriptionChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistDescriptionChanged(int)));
}

int PlaylistContainerModel::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_playlists.count();
}

QVariant PlaylistContainerModel::data(const QModelIndex &index, int role) const
{
    const sp::Playlist & playlist = m_playlists.at(index.row())->watched();

    switch (role)
    {
    case PlaylistRole:
        return QVariant::fromValue(playlist);
    case IsLoadedRole:
        return playlist.isLoaded();
    case IsValidRole:
        return playlist.isValid();
    case NameRole:
        return playlist.name();
    case DescriptionRole:
        return QString(); // Fix
    case ImageUriRole:
        return QString(); // Fix

    default:
        return QVariant();
    }
}

QHash<int, QByteArray> PlaylistContainerModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles.insert(PlaylistRole, "playlist");
    roles.insert(IsLoadedRole, "isLoaded");
    roles.insert(IsValidRole, "isValid");
    roles.insert(NameRole, "name");
    roles.insert(DescriptionRole, "description");
    roles.insert(ImageUriRole, "imageUri");
    return roles;
}

sp::PlaylistContainer PlaylistContainerModel::playlistContainer() const
{
    return m_watcher->watched();
}

void PlaylistContainerModel::setPlaylistContainer(const Spotinetta::PlaylistContainer &container)
{
    if (container != playlistContainer())
    {
        beginResetModel();
        m_playlists.clear();
        m_watcher->watch(container);

        // It seems, though I'm not sure, that we get onPlaylistAdded callbacks
        // whether the container is loaded or not, so it looks like we don't need
        // to add any playlists to our list at this point (if we do it messes up the model with duplicate
        // playlists and too low count)
//        if (container.isLoaded())
//        {
//            onLoaded();
//        }

        endResetModel();

        emit playlistContainerChanged();
    }
}

void PlaylistContainerModel::updateWatcherIndices(int first, int last)
{
    if (last >= first)
    {
        // last may be < first if a playlist is inserted into an empty container,
        // in which case we do not need to do anything in particular

        for (int i = first; i <= last; ++i)
        {
            auto watcher = m_playlists.at(i);
            updateMappings(watcher.data(), i);
        }
    }
}

QSharedPointer<Spotinetta::PlaylistWatcher> PlaylistContainerModel::createWatcher(int index)
{
    const sp::Playlist playlist = playlistContainer().playlistAt(index);

    QSharedPointer<sp::PlaylistWatcher> watcher(
                new sp::PlaylistWatcher(m_session, this),
                &sp::PlaylistWatcher::deleteLater);

    connect(watcher.data(), SIGNAL(stateChanged()),
            m_stateChangedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(renamed()),
            m_renamedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(imageChanged()),
            m_imageChangedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(descriptionChanged()),
            m_descriptionChangedMapper, SLOT(map()));

    updateMappings(watcher.data(), index);

    watcher->watch(playlist);
    return watcher;
}

void PlaylistContainerModel::updateMappings(Spotinetta::PlaylistWatcher *watcher, int index)
{
    m_stateChangedMapper->setMapping(watcher, index);
    m_renamedMapper->setMapping(watcher, index);
    m_imageChangedMapper->setMapping(watcher, index);
    m_descriptionChangedMapper->setMapping(watcher, index);
}

void PlaylistContainerModel::onLoaded()
{
    Q_ASSERT(!m_session.isNull());
    const sp::PlaylistContainer container = m_watcher->watched();

    if (container.playlistCount() > 0)
    {
        beginInsertRows(QModelIndex(), 0, container.playlistCount() - 1);
        m_playlists.reserve(container.playlistCount());

        for (int i = 0; i < container.playlistCount(); ++i)
        {
            m_playlists.append(createWatcher(i));
        }
        endInsertRows();
    }
}

void PlaylistContainerModel::onPlaylistAdded(int position)
{
    beginInsertRows(QModelIndex(), position, position);

    m_playlists.insert(position, createWatcher(position));
    updateWatcherIndices(position + 1, m_playlists.count() - 1);

    endInsertRows();
}

void PlaylistContainerModel::onPlaylistRemoved(int position)
{
    beginRemoveRows(QModelIndex(), position, position);

    m_playlists.remove(position);
    updateWatcherIndices(position, m_playlists.count() - 1);

    endRemoveRows();
}

void PlaylistContainerModel::onPlaylistMoved(int oldPosition, int newPosition)
{
    beginMoveRows(QModelIndex(), oldPosition, oldPosition, QModelIndex(), newPosition);
    QSharedPointer<sp::PlaylistWatcher> watcher = m_playlists.at(oldPosition);
    m_playlists.remove(oldPosition);
    m_playlists.insert(newPosition, watcher);

    updateWatcherIndices(oldPosition, newPosition);

    endMoveRows();
}

void PlaylistContainerModel::onPlaylistStateChanged(int position)
{
    // Update all roles for simplicity
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi);
}

void PlaylistContainerModel::onPlaylistRenamed(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, NameRole));
}

void PlaylistContainerModel::onPlaylistDescriptionChanged(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, DescriptionRole));
}

void PlaylistContainerModel::onPlaylistImageChanged(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, ImageUriRole));
}

}
<commit_msg>Some minor changes to playlistcontainermodel.cpp that hopefully fixes some rare bug that seems to appear once in a blue moon<commit_after>#include "playlistcontainermodel.h"

#include <QDebug>

namespace sp = Spotinetta;

namespace Sonetta {

PlaylistContainerModel::PlaylistContainerModel(const Spotinetta::Session *session, QObject *parent)
    :   QAbstractListModel(parent), m_session(session)
{
    m_watcher = new sp::PlaylistContainerWatcher(session, this);

    connect(m_watcher, &sp::PlaylistContainerWatcher::loaded,
            this, &PlaylistContainerModel::onLoaded);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistAdded,
            this, &PlaylistContainerModel::onPlaylistAdded);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistMoved,
            this, &PlaylistContainerModel::onPlaylistMoved);
    connect(m_watcher, &sp::PlaylistContainerWatcher::playlistRemoved,
            this, &PlaylistContainerModel::onPlaylistRemoved);

    m_stateChangedMapper = new QSignalMapper(this);
    m_renamedMapper = new QSignalMapper(this);
    m_imageChangedMapper = new QSignalMapper(this);
    m_descriptionChangedMapper = new QSignalMapper(this);

    connect(m_stateChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistStateChanged(int)));
    connect(m_renamedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistRenamed(int)));
    connect(m_imageChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistImageChanged(int)));
    connect(m_descriptionChangedMapper, SIGNAL(mapped(int)),
            this, SLOT(onPlaylistDescriptionChanged(int)));
}

int PlaylistContainerModel::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_playlists.count();
}

QVariant PlaylistContainerModel::data(const QModelIndex &index, int role) const
{
    const sp::Playlist & playlist = m_playlists.at(index.row())->watched();

    switch (role)
    {
    case PlaylistRole:
        return QVariant::fromValue(playlist);
    case IsLoadedRole:
        return playlist.isLoaded();
    case IsValidRole:
        return playlist.isValid();
    case NameRole:
        return playlist.name();
    case DescriptionRole:
        return QString(); // Fix
    case ImageUriRole:
        return QString(); // Fix

    default:
        return QVariant();
    }
}

QHash<int, QByteArray> PlaylistContainerModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles.insert(PlaylistRole, "playlist");
    roles.insert(IsLoadedRole, "isLoaded");
    roles.insert(IsValidRole, "isValid");
    roles.insert(NameRole, "name");
    roles.insert(DescriptionRole, "description");
    roles.insert(ImageUriRole, "imageUri");
    return roles;
}

sp::PlaylistContainer PlaylistContainerModel::playlistContainer() const
{
    return m_watcher->watched();
}

void PlaylistContainerModel::setPlaylistContainer(const Spotinetta::PlaylistContainer &container)
{
    if (container != playlistContainer())
    {
        beginResetModel();
        m_playlists.clear();
        endResetModel();
        m_watcher->watch(container);

        emit playlistContainerChanged();
    }
}

void PlaylistContainerModel::updateWatcherIndices(int first, int last)
{
    if (last >= first)
    {
        // last may be < first if a playlist is inserted into an empty container,
        // in which case we do not need to do anything in particular

        for (int i = first; i <= last; ++i)
        {
            auto watcher = m_playlists.at(i);
            updateMappings(watcher.data(), i);
        }
    }
}

QSharedPointer<Spotinetta::PlaylistWatcher> PlaylistContainerModel::createWatcher(int index)
{
    const sp::Playlist playlist = playlistContainer().playlistAt(index);

    QSharedPointer<sp::PlaylistWatcher> watcher(
                new sp::PlaylistWatcher(m_session, this),
                &sp::PlaylistWatcher::deleteLater);

    connect(watcher.data(), SIGNAL(stateChanged()),
            m_stateChangedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(renamed()),
            m_renamedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(imageChanged()),
            m_imageChangedMapper, SLOT(map()));
    connect(watcher.data(), SIGNAL(descriptionChanged()),
            m_descriptionChangedMapper, SLOT(map()));

    updateMappings(watcher.data(), index);

    watcher->watch(playlist);
    return watcher;
}

void PlaylistContainerModel::updateMappings(Spotinetta::PlaylistWatcher *watcher, int index)
{
    m_stateChangedMapper->setMapping(watcher, index);
    m_renamedMapper->setMapping(watcher, index);
    m_imageChangedMapper->setMapping(watcher, index);
    m_descriptionChangedMapper->setMapping(watcher, index);
}

void PlaylistContainerModel::onLoaded()
{
    Q_ASSERT(!m_session.isNull());
    const sp::PlaylistContainer container = m_watcher->watched();

    if (container.playlistCount() > 0)
    {
        beginResetModel();
        m_playlists.reserve(container.playlistCount());

        for (int i = 0; i < container.playlistCount(); ++i)
        {
            m_playlists.append(createWatcher(i));
        }
        endResetModel();
    }
}

void PlaylistContainerModel::onPlaylistAdded(int position)
{
    beginInsertRows(QModelIndex(), position, position);

    m_playlists.insert(position, createWatcher(position));
    updateWatcherIndices(position + 1, m_playlists.count() - 1);

    endInsertRows();
}

void PlaylistContainerModel::onPlaylistRemoved(int position)
{
    beginRemoveRows(QModelIndex(), position, position);

    m_playlists.remove(position);
    updateWatcherIndices(position, m_playlists.count() - 1);

    endRemoveRows();
}

void PlaylistContainerModel::onPlaylistMoved(int oldPosition, int newPosition)
{
    beginMoveRows(QModelIndex(), oldPosition, oldPosition, QModelIndex(), newPosition);
    QSharedPointer<sp::PlaylistWatcher> watcher = m_playlists.at(oldPosition);
    m_playlists.remove(oldPosition);
    m_playlists.insert(newPosition, watcher);

    updateWatcherIndices(oldPosition, newPosition);

    endMoveRows();
}

void PlaylistContainerModel::onPlaylistStateChanged(int position)
{
    // Update all roles for simplicity
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi);
}

void PlaylistContainerModel::onPlaylistRenamed(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, NameRole));
}

void PlaylistContainerModel::onPlaylistDescriptionChanged(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, DescriptionRole));
}

void PlaylistContainerModel::onPlaylistImageChanged(int position)
{
    QModelIndex mi = index(position);
    emit dataChanged(mi, mi, QVector<int>(1, ImageUriRole));
}

}
<|endoftext|>


<commit_before><commit_msg>:art: Initialize elements of vectors with constructor<commit_after><|endoftext|>


<commit_before>#include "dispatch_queue.h"

#include <thread>
#include <queue>

struct dispatch_queue_t::impl
{
    impl();
    static void dispatch_thread_proc(impl *self);

    std::queue< std::function< void() > > queue;
    std::mutex queue_mtx;
    std::condition_variable queue_cond;
    std::atomic< bool > quit;
    std::thread queue_thread;

    using queue_lock_t = std::unique_lock< decltype(queue_mtx) >;
};

void dispatch_queue_t::impl::dispatch_thread_proc(dispatch_queue_t::impl *self)
{
    using queue_size_t = decltype(self->queue)::size_type;

    while (self->quit == false)
    {
        queue_lock_t queue_lock(self->queue_mtx);
        self->queue_cond.wait(queue_lock, [&] { return self->queue.size() > 0; });

        while (self->queue.size()) {
            auto dispatch_func = self->queue.front();
            self->queue.pop();

            queue_lock.unlock();
            dispatch_func();
            queue_lock.lock();
        }
    }
}

dispatch_queue_t::impl::impl()
    : quit(false)
    , queue_thread(&dispatch_thread_proc, this)
{
}

dispatch_queue_t::dispatch_queue_t()
    : m(new impl)
{
}

dispatch_queue_t::~dispatch_queue_t()
{
    dispatch_async([this] { m->quit = true; });
    m->queue_thread.join();
}

void dispatch_queue_t::dispatch_async(std::function< void() > func)
{
    impl::queue_lock_t queue_lock(m->queue_mtx);
    m->queue.push(func);
    m->queue_cond.notify_one();
}

void dispatch_queue_t::dispatch_sync(std::function< void() > func)
{
    std::mutex sync_mtx;
    impl::queue_lock_t sync_lock(sync_mtx);
    std::condition_variable sync_cond;
    std::atomic< bool > completed(false);

    {
        impl::queue_lock_t queue_lock(m->queue_mtx);
        m->queue.push(func);
        m->queue.push([&] {
            std::unique_lock< decltype(sync_mtx) > sync_cb_lock(sync_mtx);
            completed = true;
            sync_cond.notify_one();
        });

        m->queue_cond.notify_one();
    }

    sync_cond.wait(sync_lock, [&] { return completed.load(); });
}

void dispatch_queue_t::dispatch_flush()
{
    dispatch_sync([]{});
}

<commit_msg>size() => empty()<commit_after>#include "dispatch_queue.h"

#include <thread>
#include <queue>

struct dispatch_queue_t::impl
{
    impl();
    static void dispatch_thread_proc(impl *self);

    std::queue< std::function< void() > > queue;
    std::mutex queue_mtx;
    std::condition_variable queue_cond;
    std::atomic< bool > quit;
    std::thread queue_thread;

    using queue_lock_t = std::unique_lock< decltype(queue_mtx) >;
};

void dispatch_queue_t::impl::dispatch_thread_proc(dispatch_queue_t::impl *self)
{
    using queue_size_t = decltype(self->queue)::size_type;

    while (self->quit == false)
    {
        queue_lock_t queue_lock(self->queue_mtx);
        self->queue_cond.wait(queue_lock, [&] { return !self->queue.empty(); });

        while (!self->queue.empty()) {
            auto dispatch_func = self->queue.front();
            self->queue.pop();

            queue_lock.unlock();
            dispatch_func();
            queue_lock.lock();
        }
    }
}

dispatch_queue_t::impl::impl()
    : quit(false)
    , queue_thread(&dispatch_thread_proc, this)
{
}

dispatch_queue_t::dispatch_queue_t()
    : m(new impl)
{
}

dispatch_queue_t::~dispatch_queue_t()
{
    dispatch_async([this] { m->quit = true; });
    m->queue_thread.join();
}

void dispatch_queue_t::dispatch_async(std::function< void() > func)
{
    impl::queue_lock_t queue_lock(m->queue_mtx);
    m->queue.push(func);
    m->queue_cond.notify_one();
}

void dispatch_queue_t::dispatch_sync(std::function< void() > func)
{
    std::mutex sync_mtx;
    impl::queue_lock_t sync_lock(sync_mtx);
    std::condition_variable sync_cond;
    std::atomic< bool > completed(false);

    {
        impl::queue_lock_t queue_lock(m->queue_mtx);
        m->queue.push(func);
        m->queue.push([&] {
            std::unique_lock< decltype(sync_mtx) > sync_cb_lock(sync_mtx);
            completed = true;
            sync_cond.notify_one();
        });

        m->queue_cond.notify_one();
    }

    sync_cond.wait(sync_lock, [&] { return completed.load(); });
}

void dispatch_queue_t::dispatch_flush()
{
    dispatch_sync([]{});
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGraph.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkGraph.h"

#include "vtkAdjacentVertexIterator.h"
#include "vtkDataSetAttributes.h"
#include "vtkEdgeListIterator.h"
#include "vtkIdTypeArray.h"
#include "vtkInEdgeIterator.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkOutEdgeIterator.h"
#include "vtkPoints.h"
#include "vtkVertexListIterator.h"

#include <vtksys/stl/vector>
#include <vtksys/stl/utility>

using vtksys_stl::pair;
using vtksys_stl::make_pair;
using vtksys_stl::vector;

double vtkGraph::DefaultPoint[3] = {0, 0, 0};

//----------------------------------------------------------------------------
// private class vtkVertexAdjacencyList
//----------------------------------------------------------------------------
class vtkVertexAdjacencyList
{
public:
  vector<vtkInEdgeType> InEdges;
  vector<vtkOutEdgeType> OutEdges;
};

//----------------------------------------------------------------------------
// private class vtkGraphInternals
//----------------------------------------------------------------------------
class vtkGraphInternals : public vtkObject
{
public:
  static vtkGraphInternals *New();
  vtkTypeRevisionMacro(vtkGraphInternals, vtkObject);
  vector<vtkVertexAdjacencyList> Adjacency;
  vtkIdType NumberOfEdges;

protected:
  vtkGraphInternals()
    { this->NumberOfEdges = 0; }
  ~vtkGraphInternals()
    { }

private:
  vtkGraphInternals(const vtkGraphInternals&);  // Not implemented.
  void operator=(const vtkGraphInternals&);  // Not implemented.
};

vtkStandardNewMacro(vtkGraphInternals);
vtkCxxRevisionMacro(vtkGraphInternals, "1.8");

//----------------------------------------------------------------------------
// class vtkGraph
//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkGraph, Points, vtkPoints);
vtkCxxSetObjectMacro(vtkGraph, Internals, vtkGraphInternals);
vtkCxxRevisionMacro(vtkGraph, "1.8");
//----------------------------------------------------------------------------
vtkGraph::vtkGraph()
{
  this->VertexData = vtkDataSetAttributes::New();
  this->EdgeData = vtkDataSetAttributes::New();
  this->Points = 0;
  vtkMath::UninitializeBounds(this->Bounds);

  this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_PIECES_EXTENT);
  this->Information->Set(vtkDataObject::DATA_PIECE_NUMBER(), -1);
  this->Information->Set(vtkDataObject::DATA_NUMBER_OF_PIECES(), 1);
  this->Information->Set(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS(), 0);

  this->Internals = vtkGraphInternals::New();
}

//----------------------------------------------------------------------------
vtkGraph::~vtkGraph()
{
  this->VertexData->Delete();
  this->EdgeData->Delete();
  if (this->Points)
    {
    this->Points->Delete();
    }
  this->Internals->Delete();
}

//----------------------------------------------------------------------------
double *vtkGraph::GetPoint(vtkIdType ptId)
{
  if (this->Points)
    {
    return this->Points->GetPoint(ptId);
    }
  return this->DefaultPoint;
}

//----------------------------------------------------------------------------
void vtkGraph::GetPoint(vtkIdType ptId, double x[3])
{
  if (this->Points)
    {
    this->Points->GetPoint(ptId, x);
    }
  else
    {
    for (int i = 0; i < 3; i++)
      {
      x[i] = this->DefaultPoint[i];
      }
    }
}

//----------------------------------------------------------------------------
vtkPoints *vtkGraph::GetPoints()
{
  if (!this->Points)
    {
    this->Points = vtkPoints::New();
    }
  if (this->Points->GetNumberOfPoints() != this->GetNumberOfVertices())
    {
    this->Points->SetNumberOfPoints(this->GetNumberOfVertices());
    for (vtkIdType i = 0; i < this->GetNumberOfVertices(); i++)
      {
      this->Points->SetPoint(i, 0, 0, 0);
      }
    }
  return this->Points;
}

//----------------------------------------------------------------------------
void vtkGraph::ComputeBounds()
{
  double *bounds;

  if ( this->Points )
    {
    bounds = this->Points->GetBounds();
    for (int i=0; i<6; i++)
      {
      this->Bounds[i] = bounds[i];
      }
    this->ComputeTime.Modified();
    }
}

//----------------------------------------------------------------------------
double *vtkGraph::GetBounds()
{
  this->ComputeBounds();
  return this->Bounds;
}

//----------------------------------------------------------------------------
void vtkGraph::GetBounds(double bounds[6])
{
  this->ComputeBounds();
  for (int i=0; i<6; i++)
    {
    bounds[i] = this->Bounds[i];
    }
}

//----------------------------------------------------------------------------
unsigned long int vtkGraph::GetMTime()
{
  unsigned long int doTime = vtkDataObject::GetMTime();

  if ( this->VertexData->GetMTime() > doTime )
    {
    doTime = this->VertexData->GetMTime();
    }
  if ( this->EdgeData->GetMTime() > doTime )
    {
    doTime = this->EdgeData->GetMTime();
    }
  if ( this->Points )
    {
    if ( this->Points->GetMTime() > doTime )
      {
      doTime = this->Points->GetMTime();
      }
    }

  return doTime;
}

//----------------------------------------------------------------------------
void vtkGraph::Initialize()
{
  this->ForceOwnership();
  Superclass::Initialize();
  this->EdgeData->Initialize();
  this->VertexData->Initialize();
  this->Internals->NumberOfEdges = 0;
  this->Internals->Adjacency.clear();
}

//----------------------------------------------------------------------------
void vtkGraph::GetOutEdges(vtkIdType v, vtkOutEdgeIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetOutEdges(vtkIdType v, const vtkOutEdgeType *& edges, vtkIdType & nedges)
{
  nedges = this->Internals->Adjacency[v].OutEdges.size();
  if (nedges > 0)
    {
    edges = &(this->Internals->Adjacency[v].OutEdges[0]);
    }
  else
    {
    edges = 0;
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetOutDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].OutEdges.size();
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].InEdges.size() +
         this->Internals->Adjacency[v].OutEdges.size();
}

//----------------------------------------------------------------------------
void vtkGraph::GetInEdges(vtkIdType v, vtkInEdgeIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetInEdges(vtkIdType v, const vtkInEdgeType *& edges, vtkIdType & nedges)
{
  nedges = this->Internals->Adjacency[v].InEdges.size();
  if (nedges > 0)
    {
    edges = &(this->Internals->Adjacency[v].InEdges[0]);
    }
  else
    {
    edges = 0;
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetInDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].InEdges.size();
}

//----------------------------------------------------------------------------
void vtkGraph::GetAdjacentVertices(vtkIdType v, vtkAdjacentVertexIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetEdges(vtkEdgeListIterator *it)
{
  if (it)
    {
    it->SetGraph(this);
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetNumberOfEdges()
{
  return this->Internals->NumberOfEdges;
}

//----------------------------------------------------------------------------
void vtkGraph::GetVertices(vtkVertexListIterator *it)
{
  if (it)
    {
    it->SetGraph(this);
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetNumberOfVertices()
{
  return this->Internals->Adjacency.size();
}

//----------------------------------------------------------------------------
bool vtkGraph::CheckedShallowCopy(vtkGraph *g)
{
  if (!g)
    {
    return false;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, false);
    }
  return valid;
}

//----------------------------------------------------------------------------
bool vtkGraph::CheckedDeepCopy(vtkGraph *g)
{
  if (!g)
    {
    return false;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, true);
    }
  return valid;
}

//----------------------------------------------------------------------------
void vtkGraph::ShallowCopy(vtkDataObject *obj)
{
  vtkGraph *g = vtkGraph::SafeDownCast(obj);
  if (!g)
    {
    vtkErrorMacro("Can only shallow copy from vtkGraph subclass.");
    return;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, false);
    }
  else
    {
    vtkErrorMacro("Invalid graph structure for this type of graph.");
    }
}

//----------------------------------------------------------------------------
void vtkGraph::DeepCopy(vtkDataObject *obj)
{
  vtkGraph *g = vtkGraph::SafeDownCast(obj);
  if (!g)
    {
    vtkErrorMacro("Can only shallow copy from vtkGraph subclass.");
    return;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, true);
    }
  else
    {
    vtkErrorMacro("Invalid graph structure for this type of graph.");
    }
}

//----------------------------------------------------------------------------
void vtkGraph::CopyInternal(vtkGraph *g, bool deep)
{
  if (deep)
    {
    vtkDataObject::DeepCopy(g);
    }
  else
    {
    vtkDataObject::ShallowCopy(g);
    }
  // Copy on write.
  this->SetInternals(g->Internals);
  if (deep)
    {
    this->EdgeData->DeepCopy(g->EdgeData);
    this->VertexData->DeepCopy(g->VertexData);
    }
  else
    {
    this->EdgeData->ShallowCopy(g->EdgeData);
    this->VertexData->ShallowCopy(g->VertexData);
    }
  if (g->Points)
    {
    if (!this->Points)
      {
      this->Points = vtkPoints::New();
      }
    if (deep)
      {
      this->Points->DeepCopy(g->Points);
      }
    else
      {
      this->Points->ShallowCopy(g->Points);
      }
    }
  else if (this->Points)
    {
    this->Points->Delete();
    this->Points = 0;
    }
}

//----------------------------------------------------------------------------
void vtkGraph::Squeeze()
{
  if ( this->Points )
    {
    this->Points->Squeeze();
    }
  this->EdgeData->Squeeze();
  this->VertexData->Squeeze();
}

//----------------------------------------------------------------------------
vtkGraph *vtkGraph::GetData(vtkInformation *info)
{
  return info? vtkGraph::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
}

//----------------------------------------------------------------------------
vtkGraph *vtkGraph::GetData(vtkInformationVector *v, int i)
{
  return vtkGraph::GetData(v->GetInformationObject(i));
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::AddVertexInternal()
{
  this->ForceOwnership();
  this->Internals->Adjacency.push_back(vtkVertexAdjacencyList());
  return this->Internals->Adjacency.size() - 1;
}

//----------------------------------------------------------------------------
vtkEdgeType vtkGraph::AddEdgeInternal(vtkIdType u, vtkIdType v, bool directed)
{
  this->ForceOwnership();
  vtkIdType edgeId = this->Internals->NumberOfEdges;
  this->Internals->NumberOfEdges++;
  this->Internals->Adjacency[u].OutEdges.push_back(vtkOutEdgeType(v, edgeId));
  if (directed)
    {
    this->Internals->Adjacency[v].InEdges.push_back(vtkInEdgeType(u, edgeId));
    }
  else if (u != v)
    {
    // Avoid storing self-loops twice in undirected graphs.
    this->Internals->Adjacency[v].OutEdges.push_back(vtkOutEdgeType(u, edgeId));
    }
  return vtkEdgeType(u, v, edgeId);
}

//----------------------------------------------------------------------------
void vtkGraph::ReorderOutVertices(vtkIdType v, vtkIdTypeArray *vertices)
{
  this->ForceOwnership();
  vector<vtkOutEdgeType> outEdges;
  vector<vtkOutEdgeType>::iterator it, itEnd;
  itEnd = this->Internals->Adjacency[v].OutEdges.end();
  for (vtkIdType i = 0; i < vertices->GetNumberOfTuples(); ++i)
    {
    vtkIdType vert = vertices->GetValue(i);
    // Find the matching edge
    for (it = this->Internals->Adjacency[v].OutEdges.begin(); it != itEnd; ++it)
      {
      if (it->Target == vert)
        {
        outEdges.push_back(*it);
        break;
        }
      }
    }
  if (outEdges.size() != this->Internals->Adjacency[v].OutEdges.size())
    {
    vtkErrorMacro("Invalid reorder list.");
    return;
    }
  this->Internals->Adjacency[v].OutEdges = outEdges;
}

//----------------------------------------------------------------------------
bool vtkGraph::IsSameStructure(vtkGraph *other)
{
  return (this->Internals == other->Internals);
}

//----------------------------------------------------------------------------
void vtkGraph::ForceOwnership()
{
  // If the reference count == 1, we own it and can change it.
  // If the reference count > 1, we must make a copy to avoid
  // changing the structure of other graphs.
  if (this->Internals->GetReferenceCount() > 1)
    {
    vtkGraphInternals *internals = vtkGraphInternals::New();
    internals->Adjacency = this->Internals->Adjacency;
    internals->NumberOfEdges = this->Internals->NumberOfEdges;
    this->SetInternals(internals);
    internals->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
// Supporting operators
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
bool operator==(vtkEdgeBase e1, vtkEdgeBase e2)
{
  return e1.Id == e2.Id;
}

//----------------------------------------------------------------------------
bool operator!=(vtkEdgeBase e1, vtkEdgeBase e2)
{
  return e1.Id != e2.Id;
}

//----------------------------------------------------------------------------
ostream& operator<<(ostream& out, vtkEdgeBase e)
{
  return out << e.Id;
}
<commit_msg>COMP: Attempting to fix VC6.0 error by explicitly using namespace.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGraph.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkGraph.h"

#include "vtkAdjacentVertexIterator.h"
#include "vtkDataSetAttributes.h"
#include "vtkEdgeListIterator.h"
#include "vtkIdTypeArray.h"
#include "vtkInEdgeIterator.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkOutEdgeIterator.h"
#include "vtkPoints.h"
#include "vtkVertexListIterator.h"

#include <vtksys/stl/vector>
#include <vtksys/stl/utility>

using vtksys_stl::pair;
using vtksys_stl::make_pair;
using vtksys_stl::vector;

double vtkGraph::DefaultPoint[3] = {0, 0, 0};

//----------------------------------------------------------------------------
// private class vtkVertexAdjacencyList
//----------------------------------------------------------------------------
class vtkVertexAdjacencyList
{
public:
  vector<vtkInEdgeType> InEdges;
  vector<vtkOutEdgeType> OutEdges;
};

//----------------------------------------------------------------------------
// private class vtkGraphInternals
//----------------------------------------------------------------------------
class vtkGraphInternals : public vtkObject
{
public:
  static vtkGraphInternals *New();
  vtkTypeRevisionMacro(vtkGraphInternals, vtkObject);
  vector<vtkVertexAdjacencyList> Adjacency;
  vtkIdType NumberOfEdges;

protected:
  vtkGraphInternals()
    { this->NumberOfEdges = 0; }
  ~vtkGraphInternals()
    { }

private:
  vtkGraphInternals(const vtkGraphInternals&);  // Not implemented.
  void operator=(const vtkGraphInternals&);  // Not implemented.
};

vtkStandardNewMacro(vtkGraphInternals);
vtkCxxRevisionMacro(vtkGraphInternals, "1.9");

//----------------------------------------------------------------------------
// class vtkGraph
//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkGraph, Points, vtkPoints);
vtkCxxSetObjectMacro(vtkGraph, Internals, vtkGraphInternals);
vtkCxxRevisionMacro(vtkGraph, "1.9");
//----------------------------------------------------------------------------
vtkGraph::vtkGraph()
{
  this->VertexData = vtkDataSetAttributes::New();
  this->EdgeData = vtkDataSetAttributes::New();
  this->Points = 0;
  vtkMath::UninitializeBounds(this->Bounds);

  this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_PIECES_EXTENT);
  this->Information->Set(vtkDataObject::DATA_PIECE_NUMBER(), -1);
  this->Information->Set(vtkDataObject::DATA_NUMBER_OF_PIECES(), 1);
  this->Information->Set(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS(), 0);

  this->Internals = vtkGraphInternals::New();
}

//----------------------------------------------------------------------------
vtkGraph::~vtkGraph()
{
  this->VertexData->Delete();
  this->EdgeData->Delete();
  if (this->Points)
    {
    this->Points->Delete();
    }
  this->Internals->Delete();
}

//----------------------------------------------------------------------------
double *vtkGraph::GetPoint(vtkIdType ptId)
{
  if (this->Points)
    {
    return this->Points->GetPoint(ptId);
    }
  return this->DefaultPoint;
}

//----------------------------------------------------------------------------
void vtkGraph::GetPoint(vtkIdType ptId, double x[3])
{
  if (this->Points)
    {
    this->Points->GetPoint(ptId, x);
    }
  else
    {
    for (int i = 0; i < 3; i++)
      {
      x[i] = this->DefaultPoint[i];
      }
    }
}

//----------------------------------------------------------------------------
vtkPoints *vtkGraph::GetPoints()
{
  if (!this->Points)
    {
    this->Points = vtkPoints::New();
    }
  if (this->Points->GetNumberOfPoints() != this->GetNumberOfVertices())
    {
    this->Points->SetNumberOfPoints(this->GetNumberOfVertices());
    for (vtkIdType i = 0; i < this->GetNumberOfVertices(); i++)
      {
      this->Points->SetPoint(i, 0, 0, 0);
      }
    }
  return this->Points;
}

//----------------------------------------------------------------------------
void vtkGraph::ComputeBounds()
{
  double *bounds;

  if ( this->Points )
    {
    bounds = this->Points->GetBounds();
    for (int i=0; i<6; i++)
      {
      this->Bounds[i] = bounds[i];
      }
    this->ComputeTime.Modified();
    }
}

//----------------------------------------------------------------------------
double *vtkGraph::GetBounds()
{
  this->ComputeBounds();
  return this->Bounds;
}

//----------------------------------------------------------------------------
void vtkGraph::GetBounds(double bounds[6])
{
  this->ComputeBounds();
  for (int i=0; i<6; i++)
    {
    bounds[i] = this->Bounds[i];
    }
}

//----------------------------------------------------------------------------
unsigned long int vtkGraph::GetMTime()
{
  unsigned long int doTime = vtkDataObject::GetMTime();

  if ( this->VertexData->GetMTime() > doTime )
    {
    doTime = this->VertexData->GetMTime();
    }
  if ( this->EdgeData->GetMTime() > doTime )
    {
    doTime = this->EdgeData->GetMTime();
    }
  if ( this->Points )
    {
    if ( this->Points->GetMTime() > doTime )
      {
      doTime = this->Points->GetMTime();
      }
    }

  return doTime;
}

//----------------------------------------------------------------------------
void vtkGraph::Initialize()
{
  this->ForceOwnership();
  Superclass::Initialize();
  this->EdgeData->Initialize();
  this->VertexData->Initialize();
  this->Internals->NumberOfEdges = 0;
  this->Internals->Adjacency.clear();
}

//----------------------------------------------------------------------------
void vtkGraph::GetOutEdges(vtkIdType v, vtkOutEdgeIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetOutEdges(vtkIdType v, const vtkOutEdgeType *& edges, vtkIdType & nedges)
{
  nedges = this->Internals->Adjacency[v].OutEdges.size();
  if (nedges > 0)
    {
    edges = &(this->Internals->Adjacency[v].OutEdges[0]);
    }
  else
    {
    edges = 0;
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetOutDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].OutEdges.size();
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].InEdges.size() +
         this->Internals->Adjacency[v].OutEdges.size();
}

//----------------------------------------------------------------------------
void vtkGraph::GetInEdges(vtkIdType v, vtkInEdgeIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetInEdges(vtkIdType v, const vtkInEdgeType *& edges, vtkIdType & nedges)
{
  nedges = this->Internals->Adjacency[v].InEdges.size();
  if (nedges > 0)
    {
    edges = &(this->Internals->Adjacency[v].InEdges[0]);
    }
  else
    {
    edges = 0;
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetInDegree(vtkIdType v)
{
  return this->Internals->Adjacency[v].InEdges.size();
}

//----------------------------------------------------------------------------
void vtkGraph::GetAdjacentVertices(vtkIdType v, vtkAdjacentVertexIterator *it)
{
  if (it)
    {
    it->Initialize(this, v);
    }
}

//----------------------------------------------------------------------------
void vtkGraph::GetEdges(vtkEdgeListIterator *it)
{
  if (it)
    {
    it->SetGraph(this);
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetNumberOfEdges()
{
  return this->Internals->NumberOfEdges;
}

//----------------------------------------------------------------------------
void vtkGraph::GetVertices(vtkVertexListIterator *it)
{
  if (it)
    {
    it->SetGraph(this);
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::GetNumberOfVertices()
{
  return this->Internals->Adjacency.size();
}

//----------------------------------------------------------------------------
bool vtkGraph::CheckedShallowCopy(vtkGraph *g)
{
  if (!g)
    {
    return false;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, false);
    }
  return valid;
}

//----------------------------------------------------------------------------
bool vtkGraph::CheckedDeepCopy(vtkGraph *g)
{
  if (!g)
    {
    return false;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, true);
    }
  return valid;
}

//----------------------------------------------------------------------------
void vtkGraph::ShallowCopy(vtkDataObject *obj)
{
  vtkGraph *g = vtkGraph::SafeDownCast(obj);
  if (!g)
    {
    vtkErrorMacro("Can only shallow copy from vtkGraph subclass.");
    return;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, false);
    }
  else
    {
    vtkErrorMacro("Invalid graph structure for this type of graph.");
    }
}

//----------------------------------------------------------------------------
void vtkGraph::DeepCopy(vtkDataObject *obj)
{
  vtkGraph *g = vtkGraph::SafeDownCast(obj);
  if (!g)
    {
    vtkErrorMacro("Can only shallow copy from vtkGraph subclass.");
    return;
    }
  bool valid = this->IsStructureValid(g);
  if (valid)
    {
    this->CopyInternal(g, true);
    }
  else
    {
    vtkErrorMacro("Invalid graph structure for this type of graph.");
    }
}

//----------------------------------------------------------------------------
void vtkGraph::CopyInternal(vtkGraph *g, bool deep)
{
  if (deep)
    {
    vtkDataObject::DeepCopy(g);
    }
  else
    {
    vtkDataObject::ShallowCopy(g);
    }
  // Copy on write.
  this->SetInternals(g->Internals);
  if (deep)
    {
    this->EdgeData->DeepCopy(g->EdgeData);
    this->VertexData->DeepCopy(g->VertexData);
    }
  else
    {
    this->EdgeData->ShallowCopy(g->EdgeData);
    this->VertexData->ShallowCopy(g->VertexData);
    }
  if (g->Points)
    {
    if (!this->Points)
      {
      this->Points = vtkPoints::New();
      }
    if (deep)
      {
      this->Points->DeepCopy(g->Points);
      }
    else
      {
      this->Points->ShallowCopy(g->Points);
      }
    }
  else if (this->Points)
    {
    this->Points->Delete();
    this->Points = 0;
    }
}

//----------------------------------------------------------------------------
void vtkGraph::Squeeze()
{
  if ( this->Points )
    {
    this->Points->Squeeze();
    }
  this->EdgeData->Squeeze();
  this->VertexData->Squeeze();
}

//----------------------------------------------------------------------------
vtkGraph *vtkGraph::GetData(vtkInformation *info)
{
  return info? vtkGraph::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
}

//----------------------------------------------------------------------------
vtkGraph *vtkGraph::GetData(vtkInformationVector *v, int i)
{
  return vtkGraph::GetData(v->GetInformationObject(i));
}

//----------------------------------------------------------------------------
vtkIdType vtkGraph::AddVertexInternal()
{
  this->ForceOwnership();
  this->Internals->Adjacency.push_back(vtkVertexAdjacencyList());
  return this->Internals->Adjacency.size() - 1;
}

//----------------------------------------------------------------------------
vtkEdgeType vtkGraph::AddEdgeInternal(vtkIdType u, vtkIdType v, bool directed)
{
  this->ForceOwnership();
  vtkIdType edgeId = this->Internals->NumberOfEdges;
  this->Internals->NumberOfEdges++;
  this->Internals->Adjacency[u].OutEdges.push_back(vtkOutEdgeType(v, edgeId));
  if (directed)
    {
    this->Internals->Adjacency[v].InEdges.push_back(vtkInEdgeType(u, edgeId));
    }
  else if (u != v)
    {
    // Avoid storing self-loops twice in undirected graphs.
    this->Internals->Adjacency[v].OutEdges.push_back(vtkOutEdgeType(u, edgeId));
    }
  return vtkEdgeType(u, v, edgeId);
}

//----------------------------------------------------------------------------
void vtkGraph::ReorderOutVertices(vtkIdType v, vtkIdTypeArray *vertices)
{
  this->ForceOwnership();
  vtksys_stl::vector<vtkOutEdgeType> outEdges;
  vtksys_stl::vector<vtkOutEdgeType>::iterator it, itEnd;
  itEnd = this->Internals->Adjacency[v].OutEdges.end();
  for (vtkIdType i = 0; i < vertices->GetNumberOfTuples(); ++i)
    {
    vtkIdType vert = vertices->GetValue(i);
    // Find the matching edge
    for (it = this->Internals->Adjacency[v].OutEdges.begin(); it != itEnd; ++it)
      {
      if (it->Target == vert)
        {
        outEdges.push_back(*it);
        break;
        }
      }
    }
  if (outEdges.size() != this->Internals->Adjacency[v].OutEdges.size())
    {
    vtkErrorMacro("Invalid reorder list.");
    return;
    }
  this->Internals->Adjacency[v].OutEdges = outEdges;
}

//----------------------------------------------------------------------------
bool vtkGraph::IsSameStructure(vtkGraph *other)
{
  return (this->Internals == other->Internals);
}

//----------------------------------------------------------------------------
void vtkGraph::ForceOwnership()
{
  // If the reference count == 1, we own it and can change it.
  // If the reference count > 1, we must make a copy to avoid
  // changing the structure of other graphs.
  if (this->Internals->GetReferenceCount() > 1)
    {
    vtkGraphInternals *internals = vtkGraphInternals::New();
    internals->Adjacency = this->Internals->Adjacency;
    internals->NumberOfEdges = this->Internals->NumberOfEdges;
    this->SetInternals(internals);
    internals->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
// Supporting operators
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
bool operator==(vtkEdgeBase e1, vtkEdgeBase e2)
{
  return e1.Id == e2.Id;
}

//----------------------------------------------------------------------------
bool operator!=(vtkEdgeBase e1, vtkEdgeBase e2)
{
  return e1.Id != e2.Id;
}

//----------------------------------------------------------------------------
ostream& operator<<(ostream& out, vtkEdgeBase e)
{
  return out << e.Id;
}
<|endoftext|>


<commit_before><commit_msg>iox-#25: Use more auto<commit_after><|endoftext|>


<commit_before>/*
  AdPlug - Replayer for many OPL2/OPL3 audio file formats.
  Copyright (C) 1999 - 2002 Simon Peter <dn.tlp@gmx.net>, et al.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru>
*/
/*
  NOTE: Volume slides in the original player have effect on carrier volume
  only. So my volume slides slightly different from them.
*/

#include <stdlib.h>

#include "cff.h"

/* -------- Public Methods -------------------------------- */

CPlayer *CcffLoader::factory(Copl *newopl)
{
  CcffLoader *p = new CcffLoader(newopl);
  return p;
}

bool CcffLoader::load(istream &f, const char *filename)
{
	cff_unpacker unpacker;

	const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 };
	const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE };

	int i,j,k,t=0;

	unsigned char old_event_byte2[9] = {0};

	// read header
	f.read((char *)&header,sizeof(header));

	// '<CUD-FM-File>' - signed ?
	if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16))
		return false;

	unsigned char *module = new unsigned char [0x10000];

	// packed ?
	if (header.packed)
	{
		unsigned char *packed_module = new unsigned char [header.size + 4];

		memset(packed_module,0,header.size + 4);

		f.read((char *)packed_module,header.size);

		if (!unpacker.unpack(packed_module,module))
		{
			delete packed_module;
			delete module;
			return false;
		}

		delete packed_module;
	}
	else
	{
		f.read((char *)module,header.size);
	}

	// init CmodPlayer
	realloc_instruments(47);
	realloc_order(64);
	realloc_patterns(36,64,9);

	init_notetable(conv_note);
	init_trackord();

	// load instruments
	for (i=0;i<47;i++)
	{
		memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument));

		for(j=0;j<11;j++)
			inst[i].data[conv_inst[j]] = instruments[i].data[j];

		instruments[i].name[20] = 0;
	}

	// number of patterns
	nop = module[0x5E0];

	// load title & author
	memcpy(song_title,&module[0x614],20);
	memcpy(song_author,&module[0x600],20);

	// load order
	memcpy(order,&module[0x628],64);

	// load tracks
	for (i=0;i<nop;i++)
	{
		for (j=0;j<9;j++)
		{
			for (k=0;k<64;k++)
			{
				cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3];

				// convert note
				if (event->byte0 == 0x6D)
					tracks[t][k].note = 127;
				else
					if (event->byte0)
						tracks[t][k].note = event->byte0;

				if (event->byte2)
					old_event_byte2[j] = event->byte2;

				// convert effect
				switch (event->byte1)
				{
					case 'I': // set instrument
						tracks[t][k].inst = event->byte2 + 1;
						tracks[t][k].param1 = tracks[t][k].param2 = 0;
						break;

					case 'H': // set tempo
						tracks[t][k].command = 7;
						if (event->byte2 < 16)
						{
							tracks[t][k].param1 = 0x07;
	  						tracks[t][k].param2 = 0x0D;
						}
						break;

					case 'A': // set speed
						tracks[t][k].command = 19;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'L': // pattern break
						tracks[t][k].command = 13;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'K': // order jump
						tracks[t][k].command = 11;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'M': // set vibrato/tremolo
						tracks[t][k].command = 27;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'C': // set modulator volume
						tracks[t][k].command = 21;
						tracks[t][k].param1 = (0x3F - event->byte2) >> 4;
						tracks[t][k].param2 = (0x3F - event->byte2) & 15;
						break;

					case 'G': // set carrier volume
						tracks[t][k].command = 22;
						tracks[t][k].param1 = (0x3F - event->byte2) >> 4;
						tracks[t][k].param2 = (0x3F - event->byte2) & 15;
						break;

					case 'B': // set carrier waveform
						tracks[t][k].command = 25;
						tracks[t][k].param1  = event->byte2;
						tracks[t][k].param2  = 0x0F;
						break;

					case 'E': // fine frequency slide down
						tracks[t][k].command = 24;
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;

					case 'F': // fine frequency slide up
						tracks[t][k].command = 23;
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;

					case 'D': // fine volume slide
						tracks[t][k].command = 14;
						if (old_event_byte2[j] & 15)
						{
							// slide down
							tracks[t][k].param1 = 5;
							tracks[t][k].param2 = old_event_byte2[j] & 15;
						}
						else
						{
							// slide up
							tracks[t][k].param1 = 4;
							tracks[t][k].param2 = old_event_byte2[j] >> 4;
						}
						break;

					case 'J': // arpeggio
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;
				}
			}

			t++;
		}
	}

	delete module;

	// default instruments
	for (i=0;i<9;i++)
	{
		if (!tracks[i][0].inst)
			tracks[i][0].inst = i + 1;
	}

	// order loop
	restartpos = 0;

	// order length
	for (i=0;i<64;i++)
	{
		if (order[i] >= 0x80)
		{
			length = i;
			break;
		}
	}

	// default tempo
	bpm = 0x7D;

	rewind(0);

	return true;
}

std::string CcffLoader::gettype()
{
	std::string xstr = "BoomTracker 4";

	if (header.packed)
		xstr += ", packed";

	return std::string(xstr);
}

std::string CcffLoader::gettitle()
{
	return std::string(song_title,20);
}

std::string CcffLoader::getauthor()
{
	return std::string(song_author,20);
}

std::string CcffLoader::getinstrument(unsigned int n)
{
	return std::string(instruments[n].name);
}

unsigned int CcffLoader::getinstruments()
{
	return 47;
}

/* -------- Private Methods ------------------------------- */

#ifdef _WIN32
#pragma warning(disable:4244)
#pragma warning(disable:4018)
#endif

/*
  Lempel-Ziv-Tyr ;-)
*/
unsigned int CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf)
{
	if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16))
		return 0;

	input = ibuf + 16;
	output = obuf;

	output_length = 0;

	heap = (unsigned char *)malloc(0x10000);
	dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000);

	memset(heap,0,0x10000);
	memset(dictionary,0,0x8000);

	cleanup();
	startup();

	// LZW
	while (1)
	{
		new_code = get_code();

		// 0x00: end of data
		if (new_code == 0)
			break;

		// 0x01: end of block
		if (new_code == 1)
		{
			cleanup();
			startup();

			continue;
		}

		// 0x02: expand code length
		if (new_code == 2)
		{
			code_length++;

			continue;
		}

		// 0x03: RLE
		if (new_code == 3)
		{
			unsigned char old_code_length = code_length;

			code_length = 2;

			unsigned char repeat_length = get_code() + 1;

			code_length = 4 << get_code();

			unsigned long repeat_counter = get_code();

			for (int i=0;i<repeat_counter*repeat_length;i++)
				output[output_length++] = output[output_length - repeat_length];

			code_length = old_code_length;

			startup();

			continue;
		}

		if (new_code >= (0x104 + dictionary_length))
		{
			// dictionary <- old.code.string + old.code.char
			the_string[++the_string[0]] = the_string[1];
		}
		else
		{
			// dictionary <- old.code.string + new.code.char
			unsigned char temp_string[256];

			translate_code(new_code,temp_string);

			the_string[++the_string[0]] = temp_string[1];
		}

		expand_dictionary(the_string);

		// output <- new.code.string
		translate_code(new_code,the_string);

		for (int i=0;i<the_string[0];i++)
			output[output_length++] = the_string[i+1];

		old_code = new_code;
	}

	free(heap);
	free(dictionary);

	if (memcmp(output + 0x5E1,"CUD-FM-File - SEND A POSTCARD -",31))
		return 0;

	return output_length;
}

unsigned long CcffLoader::cff_unpacker::get_code()
{
	unsigned long code;

	while (bits_left <= 24)
	{
		bits_buffer |= ((*input++) << bits_left);
		bits_left += 8;
	}

	code = bits_buffer & ((1 << code_length) - 1);

	bits_buffer >>= code_length;
	bits_left -= code_length;

	return code;
}

void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string)
{
	unsigned char translated_string[256];

	if (code >= 0x104)
	{
		memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1);
	}
	else
	{
		translated_string[0] = 1;
		translated_string[1] = (code - 4) & 0xFF;
	}

	memcpy(string,translated_string,256);
}

void CcffLoader::cff_unpacker::cleanup()
{
	code_length = 9;

	bits_buffer = 0;
	bits_left = 0;

	heap_length = 0;
	dictionary_length = 0;
}

void CcffLoader::cff_unpacker::startup()
{
	old_code = get_code();

	translate_code(old_code,the_string);

	for (int i=0;i<the_string[0];i++)
		output[output_length++] = the_string[i+1];
}

void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string)
{
	memcpy(&heap[heap_length],string,string[0] + 1);

	dictionary[dictionary_length] = &heap[heap_length];

	dictionary_length++;

	heap_length += (string[0] + 1);
}

#ifdef _WIN32
#pragma warning(default:4244)
#pragma warning(default:4018)
#endif
<commit_msg>comment changes<commit_after>/*
  AdPlug - Replayer for many OPL2/OPL3 audio file formats.
  Copyright (C) 1999 - 2002 Simon Peter <dn.tlp@gmx.net>, et al.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru>
*/
/*
  NOTE: Conversion of slides is not 100% accurate. Original volume slides
  have effect on carrier volume only. Also, original frequency & volume
  slides use previous effect data instead of current.
*/

#include <stdlib.h>

#include "cff.h"

/* -------- Public Methods -------------------------------- */

CPlayer *CcffLoader::factory(Copl *newopl)
{
  CcffLoader *p = new CcffLoader(newopl);
  return p;
}

bool CcffLoader::load(istream &f, const char *filename)
{
	cff_unpacker unpacker;

	const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 };
	const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE };

	int i,j,k,t=0;

	unsigned char old_event_byte2[9] = {0};

	// read header
	f.read((char *)&header,sizeof(header));

	// '<CUD-FM-File>' - signed ?
	if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16))
		return false;

	unsigned char *module = new unsigned char [0x10000];

	// packed ?
	if (header.packed)
	{
		unsigned char *packed_module = new unsigned char [header.size + 4];

		memset(packed_module,0,header.size + 4);

		f.read((char *)packed_module,header.size);

		if (!unpacker.unpack(packed_module,module))
		{
			delete packed_module;
			delete module;
			return false;
		}

		delete packed_module;
	}
	else
	{
		f.read((char *)module,header.size);
	}

	// init CmodPlayer
	realloc_instruments(47);
	realloc_order(64);
	realloc_patterns(36,64,9);

	init_notetable(conv_note);
	init_trackord();

	// load instruments
	for (i=0;i<47;i++)
	{
		memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument));

		for(j=0;j<11;j++)
			inst[i].data[conv_inst[j]] = instruments[i].data[j];

		instruments[i].name[20] = 0;
	}

	// number of patterns
	nop = module[0x5E0];

	// load title & author
	memcpy(song_title,&module[0x614],20);
	memcpy(song_author,&module[0x600],20);

	// load order
	memcpy(order,&module[0x628],64);

	// load tracks
	for (i=0;i<nop;i++)
	{
		for (j=0;j<9;j++)
		{
			for (k=0;k<64;k++)
			{
				cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3];

				// convert note
				if (event->byte0 == 0x6D)
					tracks[t][k].note = 127;
				else
					if (event->byte0)
						tracks[t][k].note = event->byte0;

				if (event->byte2)
					old_event_byte2[j] = event->byte2;

				// convert effect
				switch (event->byte1)
				{
					case 'I': // set instrument
						tracks[t][k].inst = event->byte2 + 1;
						tracks[t][k].param1 = tracks[t][k].param2 = 0;
						break;

					case 'H': // set tempo
						tracks[t][k].command = 7;
						if (event->byte2 < 16)
						{
							tracks[t][k].param1 = 0x07;
	  						tracks[t][k].param2 = 0x0D;
						}
						break;

					case 'A': // set speed
						tracks[t][k].command = 19;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'L': // pattern break
						tracks[t][k].command = 13;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'K': // order jump
						tracks[t][k].command = 11;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'M': // set vibrato/tremolo
						tracks[t][k].command = 27;
						tracks[t][k].param1  = event->byte2 >> 4;
						tracks[t][k].param2  = event->byte2 & 15;
						break;

					case 'C': // set modulator volume
						tracks[t][k].command = 21;
						tracks[t][k].param1 = (0x3F - event->byte2) >> 4;
						tracks[t][k].param2 = (0x3F - event->byte2) & 15;
						break;

					case 'G': // set carrier volume
						tracks[t][k].command = 22;
						tracks[t][k].param1 = (0x3F - event->byte2) >> 4;
						tracks[t][k].param2 = (0x3F - event->byte2) & 15;
						break;

					case 'B': // set carrier waveform
						tracks[t][k].command = 25;
						tracks[t][k].param1  = event->byte2;
						tracks[t][k].param2  = 0x0F;
						break;

					case 'E': // fine frequency slide down
						tracks[t][k].command = 24;
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;

					case 'F': // fine frequency slide up
						tracks[t][k].command = 23;
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;

					case 'D': // fine volume slide
						tracks[t][k].command = 14;
						if (old_event_byte2[j] & 15)
						{
							// slide down
							tracks[t][k].param1 = 5;
							tracks[t][k].param2 = old_event_byte2[j] & 15;
						}
						else
						{
							// slide up
							tracks[t][k].param1 = 4;
							tracks[t][k].param2 = old_event_byte2[j] >> 4;
						}
						break;

					case 'J': // arpeggio
						tracks[t][k].param1  = old_event_byte2[j] >> 4;
						tracks[t][k].param2  = old_event_byte2[j] & 15;
						break;
				}
			}

			t++;
		}
	}

	delete module;

	// default instruments
	for (i=0;i<9;i++)
	{
		if (!tracks[i][0].inst)
			tracks[i][0].inst = i + 1;
	}

	// order loop
	restartpos = 0;

	// order length
	for (i=0;i<64;i++)
	{
		if (order[i] >= 0x80)
		{
			length = i;
			break;
		}
	}

	// default tempo
	bpm = 0x7D;

	rewind(0);

	return true;
}

std::string CcffLoader::gettype()
{
	std::string xstr = "BoomTracker 4";

	if (header.packed)
		xstr += ", packed";

	return std::string(xstr);
}

std::string CcffLoader::gettitle()
{
	return std::string(song_title,20);
}

std::string CcffLoader::getauthor()
{
	return std::string(song_author,20);
}

std::string CcffLoader::getinstrument(unsigned int n)
{
	return std::string(instruments[n].name);
}

unsigned int CcffLoader::getinstruments()
{
	return 47;
}

/* -------- Private Methods ------------------------------- */

#ifdef _WIN32
#pragma warning(disable:4244)
#pragma warning(disable:4018)
#endif

/*
  Lempel-Ziv-Tyr ;-)
*/
unsigned int CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf)
{
	if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16))
		return 0;

	input = ibuf + 16;
	output = obuf;

	output_length = 0;

	heap = (unsigned char *)malloc(0x10000);
	dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000);

	memset(heap,0,0x10000);
	memset(dictionary,0,0x8000);

	cleanup();
	startup();

	// LZW
	while (1)
	{
		new_code = get_code();

		// 0x00: end of data
		if (new_code == 0)
			break;

		// 0x01: end of block
		if (new_code == 1)
		{
			cleanup();
			startup();

			continue;
		}

		// 0x02: expand code length
		if (new_code == 2)
		{
			code_length++;

			continue;
		}

		// 0x03: RLE
		if (new_code == 3)
		{
			unsigned char old_code_length = code_length;

			code_length = 2;

			unsigned char repeat_length = get_code() + 1;

			code_length = 4 << get_code();

			unsigned long repeat_counter = get_code();

			for (int i=0;i<repeat_counter*repeat_length;i++)
				output[output_length++] = output[output_length - repeat_length];

			code_length = old_code_length;

			startup();

			continue;
		}

		if (new_code >= (0x104 + dictionary_length))
		{
			// dictionary <- old.code.string + old.code.char
			the_string[++the_string[0]] = the_string[1];
		}
		else
		{
			// dictionary <- old.code.string + new.code.char
			unsigned char temp_string[256];

			translate_code(new_code,temp_string);

			the_string[++the_string[0]] = temp_string[1];
		}

		expand_dictionary(the_string);

		// output <- new.code.string
		translate_code(new_code,the_string);

		for (int i=0;i<the_string[0];i++)
			output[output_length++] = the_string[i+1];

		old_code = new_code;
	}

	free(heap);
	free(dictionary);

	if (memcmp(output + 0x5E1,"CUD-FM-File - SEND A POSTCARD -",31))
		return 0;

	return output_length;
}

unsigned long CcffLoader::cff_unpacker::get_code()
{
	unsigned long code;

	while (bits_left <= 24)
	{
		bits_buffer |= ((*input++) << bits_left);
		bits_left += 8;
	}

	code = bits_buffer & ((1 << code_length) - 1);

	bits_buffer >>= code_length;
	bits_left -= code_length;

	return code;
}

void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string)
{
	unsigned char translated_string[256];

	if (code >= 0x104)
	{
		memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1);
	}
	else
	{
		translated_string[0] = 1;
		translated_string[1] = (code - 4) & 0xFF;
	}

	memcpy(string,translated_string,256);
}

void CcffLoader::cff_unpacker::cleanup()
{
	code_length = 9;

	bits_buffer = 0;
	bits_left = 0;

	heap_length = 0;
	dictionary_length = 0;
}

void CcffLoader::cff_unpacker::startup()
{
	old_code = get_code();

	translate_code(old_code,the_string);

	for (int i=0;i<the_string[0];i++)
		output[output_length++] = the_string[i+1];
}

void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string)
{
	memcpy(&heap[heap_length],string,string[0] + 1);

	dictionary[dictionary_length] = &heap[heap_length];

	dictionary_length++;

	heap_length += (string[0] + 1);
}

#ifdef _WIN32
#pragma warning(default:4244)
#pragma warning(default:4018)
#endif
<|endoftext|>