<commit_before>//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Link Time Optimization library. This library is
// intended to be used by linker to optimize code at link time.
//
//===----------------------------------------------------------------------===//

#include "LTOCodeGenerator.h"
#include "LTOModule.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Config/config.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/system_error.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

static cl::opt<bool> DisableInline("disable-inlining", cl::init(false),
  cl::desc("Do not run the inliner pass"));

static cl::opt<bool> DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
  cl::desc("Do not run the GVN load PRE pass"));

const char* LTOCodeGenerator::getVersionString() {
#ifdef LLVM_VERSION_INFO
  return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO;
#else
  return PACKAGE_NAME " version " PACKAGE_VERSION;
#endif
}

LTOCodeGenerator::LTOCodeGenerator()
  : _context(getGlobalContext()),
    _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL),
    _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false),
    _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC),
    _nativeObjectFile(NULL) {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
}

LTOCodeGenerator::~LTOCodeGenerator() {
  delete _target;
  delete _nativeObjectFile;

  for (std::vector<char*>::iterator I = _codegenOptions.begin(),
         E = _codegenOptions.end(); I != E; ++I)
    free(*I);
}

bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) {
  bool ret = _linker.LinkInModule(mod->getLLVVMModule(), &errMsg);

  const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs();
  for (int i = 0, e = undefs.size(); i != e; ++i)
    _asmUndefinedRefs[undefs[i]] = 1;

  return ret;
}

bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug,
                                    std::string& errMsg) {
  switch (debug) {
  case LTO_DEBUG_MODEL_NONE:
    _emitDwarfDebugInfo = false;
    return false;

  case LTO_DEBUG_MODEL_DWARF:
    _emitDwarfDebugInfo = true;
    return false;
  }
  llvm_unreachable("Unknown debug format!");
}

bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model,
                                       std::string& errMsg) {
  switch (model) {
  case LTO_CODEGEN_PIC_MODEL_STATIC:
  case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
  case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
    _codeModel = model;
    return false;
  }
  llvm_unreachable("Unknown PIC model!");
}

bool LTOCodeGenerator::writeMergedModules(const char *path,
                                          std::string &errMsg) {
  if (determineTarget(errMsg))
    return true;

  // mark which symbols can not be internalized
  applyScopeRestrictions();

  // create output file
  std::string ErrInfo;
  tool_output_file Out(path, ErrInfo,
                       raw_fd_ostream::F_Binary);
  if (!ErrInfo.empty()) {
    errMsg = "could not open bitcode file for writing: ";
    errMsg += path;
    return true;
  }

  // write bitcode to it
  WriteBitcodeToFile(_linker.getModule(), Out.os());
  Out.os().close();

  if (Out.os().has_error()) {
    errMsg = "could not write bitcode file: ";
    errMsg += path;
    Out.os().clear_error();
    return true;
  }

  Out.keep();
  return false;
}

bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) {
  // make unique temp .o file to put generated object file
  sys::PathWithStatus uniqueObjPath("lto-llvm.o");
  if ( uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg) ) {
    uniqueObjPath.eraseFromDisk();
    return true;
  }
  sys::RemoveFileOnSignal(uniqueObjPath);

  // generate object file
  bool genResult = false;
  tool_output_file objFile(uniqueObjPath.c_str(), errMsg);
  if (!errMsg.empty())
    return true;

  genResult = this->generateObjectFile(objFile.os(), errMsg);
  objFile.os().close();
  if (objFile.os().has_error()) {
    objFile.os().clear_error();
    return true;
  }

  objFile.keep();
  if ( genResult ) {
    uniqueObjPath.eraseFromDisk();
    return true;
  }

  _nativeObjectPath = uniqueObjPath.str();
  *name = _nativeObjectPath.c_str();
  return false;
}

const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
  const char *name;
  if (compile_to_file(&name, errMsg))
    return NULL;

  // remove old buffer if compile() called twice
  delete _nativeObjectFile;

  // read .o file into memory buffer
  OwningPtr<MemoryBuffer> BuffPtr;
  if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) {
    errMsg = ec.message();
    return NULL;
  }
  _nativeObjectFile = BuffPtr.take();

  // remove temp files
  sys::Path(_nativeObjectPath).eraseFromDisk();

  // return buffer, unless error
  if ( _nativeObjectFile == NULL )
    return NULL;
  *length = _nativeObjectFile->getBufferSize();
  return _nativeObjectFile->getBufferStart();
}

bool LTOCodeGenerator::determineTarget(std::string& errMsg) {
  if ( _target == NULL ) {
    std::string Triple = _linker.getModule()->getTargetTriple();
    if (Triple.empty())
      Triple = sys::getDefaultTargetTriple();

    // create target machine from info for merged modules
    const Target *march = TargetRegistry::lookupTarget(Triple, errMsg);
    if ( march == NULL )
      return true;

    // The relocation model is actually a static member of TargetMachine and
    // needs to be set before the TargetMachine is instantiated.
    Reloc::Model RelocModel = Reloc::Default;
    switch( _codeModel ) {
    case LTO_CODEGEN_PIC_MODEL_STATIC:
      RelocModel = Reloc::Static;
      break;
    case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
      RelocModel = Reloc::PIC_;
      break;
    case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
      RelocModel = Reloc::DynamicNoPIC;
      break;
    }

    // construct LTOModule, hand over ownership of module and target
    SubtargetFeatures Features;
    Features.getDefaultSubtargetFeatures(llvm::Triple(Triple));
    std::string FeatureStr = Features.getString();
    TargetOptions Options;
    _target = march->createTargetMachine(Triple, _mCpu, FeatureStr, Options,
                                         RelocModel);
  }
  return false;
}

void LTOCodeGenerator::
applyRestriction(GlobalValue &GV,
                 std::vector<const char*> &mustPreserveList,
                 SmallPtrSet<GlobalValue*, 8> &asmUsed,
                 Mangler &mangler) {
  SmallString<64> Buffer;
  mangler.getNameWithPrefix(Buffer, &GV, false);

  if (GV.isDeclaration())
    return;
  if (_mustPreserveSymbols.count(Buffer))
    mustPreserveList.push_back(GV.getName().data());
  if (_asmUndefinedRefs.count(Buffer))
    asmUsed.insert(&GV);
}

static void findUsedValues(GlobalVariable *LLVMUsed,
                           SmallPtrSet<GlobalValue*, 8> &UsedValues) {
  if (LLVMUsed == 0) return;

  ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer());
  if (Inits == 0) return;

  for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
    if (GlobalValue *GV =
        dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))
      UsedValues.insert(GV);
}

void LTOCodeGenerator::applyScopeRestrictions() {
  if (_scopeRestrictionsDone) return;
  Module *mergedModule = _linker.getModule();

  // Start off with a verification pass.
  PassManager passes;
  passes.add(createVerifierPass());

  // mark which symbols can not be internalized
  MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL);
  Mangler mangler(Context, *_target->getTargetData());
  std::vector<const char*> mustPreserveList;
  SmallPtrSet<GlobalValue*, 8> asmUsed;

  for (Module::iterator f = mergedModule->begin(),
         e = mergedModule->end(); f != e; ++f)
    applyRestriction(*f, mustPreserveList, asmUsed, mangler);
  for (Module::global_iterator v = mergedModule->global_begin(),
         e = mergedModule->global_end(); v !=  e; ++v)
    applyRestriction(*v, mustPreserveList, asmUsed, mangler);
  for (Module::alias_iterator a = mergedModule->alias_begin(),
         e = mergedModule->alias_end(); a != e; ++a)
    applyRestriction(*a, mustPreserveList, asmUsed, mangler);

  GlobalVariable *LLVMCompilerUsed =
    mergedModule->getGlobalVariable("llvm.compiler.used");
  findUsedValues(LLVMCompilerUsed, asmUsed);
  if (LLVMCompilerUsed)
    LLVMCompilerUsed->eraseFromParent();

  llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context);
  std::vector<Constant*> asmUsed2;
  for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(),
         e = asmUsed.end(); i !=e; ++i) {
    GlobalValue *GV = *i;
    Constant *c = ConstantExpr::getBitCast(GV, i8PTy);
    asmUsed2.push_back(c);
  }

  llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size());
  LLVMCompilerUsed =
    new llvm::GlobalVariable(*mergedModule, ATy, false,
                             llvm::GlobalValue::AppendingLinkage,
                             llvm::ConstantArray::get(ATy, asmUsed2),
                             "llvm.compiler.used");

  LLVMCompilerUsed->setSection("llvm.metadata");

  passes.add(createInternalizePass(mustPreserveList));

  // apply scope restrictions
  passes.run(*mergedModule);

  _scopeRestrictionsDone = true;
}

/// Optimize merged modules using various IPO passes
bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
                                          std::string &errMsg) {
  if ( this->determineTarget(errMsg) )
    return true;

  Module* mergedModule = _linker.getModule();

  // if options were requested, set them
  if ( !_codegenOptions.empty() )
    cl::ParseCommandLineOptions(_codegenOptions.size(),
                                const_cast<char **>(&_codegenOptions[0]));

  // mark which symbols can not be internalized
  this->applyScopeRestrictions();

  // Instantiate the pass manager to organize the passes.
  PassManager passes;

  // Start off with a verification pass.
  passes.add(createVerifierPass());

  // Add an appropriate TargetData instance for this module...
  passes.add(new TargetData(*_target->getTargetData()));

  // Enabling internalize here would use its AllButMain variant. It
  // keeps only main if it exists and does nothing for libraries. Instead
  // we create the pass ourselves with the symbol list provided by the linker.
  PassManagerBuilder().populateLTOPassManager(passes, /*Internalize=*/false,
                                              !DisableInline,
                                              DisableGVNLoadPRE);

  // Make sure everything is still good.
  passes.add(createVerifierPass());

  FunctionPassManager *codeGenPasses = new FunctionPassManager(mergedModule);

  codeGenPasses->add(new TargetData(*_target->getTargetData()));

  formatted_raw_ostream Out(out);

  if (_target->addPassesToEmitFile(*codeGenPasses, Out,
                                   TargetMachine::CGFT_ObjectFile,
                                   CodeGenOpt::Aggressive)) {
    errMsg = "target file type not supported";
    return true;
  }

  // Run our queue of passes all at once now, efficiently.
  passes.run(*mergedModule);

  // Run the code generator, and write assembly file
  codeGenPasses->doInitialization();

  for (Module::iterator
         it = mergedModule->begin(), e = mergedModule->end(); it != e; ++it)
    if (!it->isDeclaration())
      codeGenPasses->run(*it);

  codeGenPasses->doFinalization();
  delete codeGenPasses;

  return false; // success
}

/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging
/// LTO problems.
void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) {
  for (std::pair<StringRef, StringRef> o = getToken(options);
       !o.first.empty(); o = getToken(o.second)) {
    // ParseCommandLineOptions() expects argv[0] to be program name. Lazily add
    // that.
    if ( _codegenOptions.empty() )
      _codegenOptions.push_back(strdup("libLTO"));
    _codegenOptions.push_back(strdup(o.first.str().c_str()));
  }
}
<commit_msg>Reinstate -O3 for LTO.<commit_after>//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Link Time Optimization library. This library is
// intended to be used by linker to optimize code at link time.
//
//===----------------------------------------------------------------------===//

#include "LTOCodeGenerator.h"
#include "LTOModule.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Config/config.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/system_error.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

static cl::opt<bool> DisableInline("disable-inlining", cl::init(false),
  cl::desc("Do not run the inliner pass"));

static cl::opt<bool> DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
  cl::desc("Do not run the GVN load PRE pass"));

const char* LTOCodeGenerator::getVersionString() {
#ifdef LLVM_VERSION_INFO
  return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO;
#else
  return PACKAGE_NAME " version " PACKAGE_VERSION;
#endif
}

LTOCodeGenerator::LTOCodeGenerator()
  : _context(getGlobalContext()),
    _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL),
    _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false),
    _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC),
    _nativeObjectFile(NULL) {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
}

LTOCodeGenerator::~LTOCodeGenerator() {
  delete _target;
  delete _nativeObjectFile;

  for (std::vector<char*>::iterator I = _codegenOptions.begin(),
         E = _codegenOptions.end(); I != E; ++I)
    free(*I);
}

bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) {
  bool ret = _linker.LinkInModule(mod->getLLVVMModule(), &errMsg);

  const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs();
  for (int i = 0, e = undefs.size(); i != e; ++i)
    _asmUndefinedRefs[undefs[i]] = 1;

  return ret;
}

bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug,
                                    std::string& errMsg) {
  switch (debug) {
  case LTO_DEBUG_MODEL_NONE:
    _emitDwarfDebugInfo = false;
    return false;

  case LTO_DEBUG_MODEL_DWARF:
    _emitDwarfDebugInfo = true;
    return false;
  }
  llvm_unreachable("Unknown debug format!");
}

bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model,
                                       std::string& errMsg) {
  switch (model) {
  case LTO_CODEGEN_PIC_MODEL_STATIC:
  case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
  case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
    _codeModel = model;
    return false;
  }
  llvm_unreachable("Unknown PIC model!");
}

bool LTOCodeGenerator::writeMergedModules(const char *path,
                                          std::string &errMsg) {
  if (determineTarget(errMsg))
    return true;

  // mark which symbols can not be internalized
  applyScopeRestrictions();

  // create output file
  std::string ErrInfo;
  tool_output_file Out(path, ErrInfo,
                       raw_fd_ostream::F_Binary);
  if (!ErrInfo.empty()) {
    errMsg = "could not open bitcode file for writing: ";
    errMsg += path;
    return true;
  }

  // write bitcode to it
  WriteBitcodeToFile(_linker.getModule(), Out.os());
  Out.os().close();

  if (Out.os().has_error()) {
    errMsg = "could not write bitcode file: ";
    errMsg += path;
    Out.os().clear_error();
    return true;
  }

  Out.keep();
  return false;
}

bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) {
  // make unique temp .o file to put generated object file
  sys::PathWithStatus uniqueObjPath("lto-llvm.o");
  if ( uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg) ) {
    uniqueObjPath.eraseFromDisk();
    return true;
  }
  sys::RemoveFileOnSignal(uniqueObjPath);

  // generate object file
  bool genResult = false;
  tool_output_file objFile(uniqueObjPath.c_str(), errMsg);
  if (!errMsg.empty())
    return true;

  genResult = this->generateObjectFile(objFile.os(), errMsg);
  objFile.os().close();
  if (objFile.os().has_error()) {
    objFile.os().clear_error();
    return true;
  }

  objFile.keep();
  if ( genResult ) {
    uniqueObjPath.eraseFromDisk();
    return true;
  }

  _nativeObjectPath = uniqueObjPath.str();
  *name = _nativeObjectPath.c_str();
  return false;
}

const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
  const char *name;
  if (compile_to_file(&name, errMsg))
    return NULL;

  // remove old buffer if compile() called twice
  delete _nativeObjectFile;

  // read .o file into memory buffer
  OwningPtr<MemoryBuffer> BuffPtr;
  if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) {
    errMsg = ec.message();
    return NULL;
  }
  _nativeObjectFile = BuffPtr.take();

  // remove temp files
  sys::Path(_nativeObjectPath).eraseFromDisk();

  // return buffer, unless error
  if ( _nativeObjectFile == NULL )
    return NULL;
  *length = _nativeObjectFile->getBufferSize();
  return _nativeObjectFile->getBufferStart();
}

bool LTOCodeGenerator::determineTarget(std::string& errMsg) {
  if ( _target == NULL ) {
    std::string Triple = _linker.getModule()->getTargetTriple();
    if (Triple.empty())
      Triple = sys::getDefaultTargetTriple();

    // create target machine from info for merged modules
    const Target *march = TargetRegistry::lookupTarget(Triple, errMsg);
    if ( march == NULL )
      return true;

    // The relocation model is actually a static member of TargetMachine and
    // needs to be set before the TargetMachine is instantiated.
    Reloc::Model RelocModel = Reloc::Default;
    switch( _codeModel ) {
    case LTO_CODEGEN_PIC_MODEL_STATIC:
      RelocModel = Reloc::Static;
      break;
    case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
      RelocModel = Reloc::PIC_;
      break;
    case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
      RelocModel = Reloc::DynamicNoPIC;
      break;
    }

    // construct LTOModule, hand over ownership of module and target
    SubtargetFeatures Features;
    Features.getDefaultSubtargetFeatures(llvm::Triple(Triple));
    std::string FeatureStr = Features.getString();
    TargetOptions Options;
    _target = march->createTargetMachine(Triple, _mCpu, FeatureStr, Options,
                                         RelocModel, CodeModel::Default,
                                         CodeGenOpt::Aggressive);
  }
  return false;
}

void LTOCodeGenerator::
applyRestriction(GlobalValue &GV,
                 std::vector<const char*> &mustPreserveList,
                 SmallPtrSet<GlobalValue*, 8> &asmUsed,
                 Mangler &mangler) {
  SmallString<64> Buffer;
  mangler.getNameWithPrefix(Buffer, &GV, false);

  if (GV.isDeclaration())
    return;
  if (_mustPreserveSymbols.count(Buffer))
    mustPreserveList.push_back(GV.getName().data());
  if (_asmUndefinedRefs.count(Buffer))
    asmUsed.insert(&GV);
}

static void findUsedValues(GlobalVariable *LLVMUsed,
                           SmallPtrSet<GlobalValue*, 8> &UsedValues) {
  if (LLVMUsed == 0) return;

  ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer());
  if (Inits == 0) return;

  for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
    if (GlobalValue *GV =
        dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))
      UsedValues.insert(GV);
}

void LTOCodeGenerator::applyScopeRestrictions() {
  if (_scopeRestrictionsDone) return;
  Module *mergedModule = _linker.getModule();

  // Start off with a verification pass.
  PassManager passes;
  passes.add(createVerifierPass());

  // mark which symbols can not be internalized
  MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL);
  Mangler mangler(Context, *_target->getTargetData());
  std::vector<const char*> mustPreserveList;
  SmallPtrSet<GlobalValue*, 8> asmUsed;

  for (Module::iterator f = mergedModule->begin(),
         e = mergedModule->end(); f != e; ++f)
    applyRestriction(*f, mustPreserveList, asmUsed, mangler);
  for (Module::global_iterator v = mergedModule->global_begin(),
         e = mergedModule->global_end(); v !=  e; ++v)
    applyRestriction(*v, mustPreserveList, asmUsed, mangler);
  for (Module::alias_iterator a = mergedModule->alias_begin(),
         e = mergedModule->alias_end(); a != e; ++a)
    applyRestriction(*a, mustPreserveList, asmUsed, mangler);

  GlobalVariable *LLVMCompilerUsed =
    mergedModule->getGlobalVariable("llvm.compiler.used");
  findUsedValues(LLVMCompilerUsed, asmUsed);
  if (LLVMCompilerUsed)
    LLVMCompilerUsed->eraseFromParent();

  llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context);
  std::vector<Constant*> asmUsed2;
  for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(),
         e = asmUsed.end(); i !=e; ++i) {
    GlobalValue *GV = *i;
    Constant *c = ConstantExpr::getBitCast(GV, i8PTy);
    asmUsed2.push_back(c);
  }

  llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size());
  LLVMCompilerUsed =
    new llvm::GlobalVariable(*mergedModule, ATy, false,
                             llvm::GlobalValue::AppendingLinkage,
                             llvm::ConstantArray::get(ATy, asmUsed2),
                             "llvm.compiler.used");

  LLVMCompilerUsed->setSection("llvm.metadata");

  passes.add(createInternalizePass(mustPreserveList));

  // apply scope restrictions
  passes.run(*mergedModule);

  _scopeRestrictionsDone = true;
}

/// Optimize merged modules using various IPO passes
bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
                                          std::string &errMsg) {
  if ( this->determineTarget(errMsg) )
    return true;

  Module* mergedModule = _linker.getModule();

  // if options were requested, set them
  if ( !_codegenOptions.empty() )
    cl::ParseCommandLineOptions(_codegenOptions.size(),
                                const_cast<char **>(&_codegenOptions[0]));

  // mark which symbols can not be internalized
  this->applyScopeRestrictions();

  // Instantiate the pass manager to organize the passes.
  PassManager passes;

  // Start off with a verification pass.
  passes.add(createVerifierPass());

  // Add an appropriate TargetData instance for this module...
  passes.add(new TargetData(*_target->getTargetData()));

  // Enabling internalize here would use its AllButMain variant. It
  // keeps only main if it exists and does nothing for libraries. Instead
  // we create the pass ourselves with the symbol list provided by the linker.
  PassManagerBuilder().populateLTOPassManager(passes, /*Internalize=*/false,
                                              !DisableInline,
                                              DisableGVNLoadPRE);

  // Make sure everything is still good.
  passes.add(createVerifierPass());

  FunctionPassManager *codeGenPasses = new FunctionPassManager(mergedModule);

  codeGenPasses->add(new TargetData(*_target->getTargetData()));

  formatted_raw_ostream Out(out);

  if (_target->addPassesToEmitFile(*codeGenPasses, Out,
                                   TargetMachine::CGFT_ObjectFile)) {
    errMsg = "target file type not supported";
    return true;
  }

  // Run our queue of passes all at once now, efficiently.
  passes.run(*mergedModule);

  // Run the code generator, and write assembly file
  codeGenPasses->doInitialization();

  for (Module::iterator
         it = mergedModule->begin(), e = mergedModule->end(); it != e; ++it)
    if (!it->isDeclaration())
      codeGenPasses->run(*it);

  codeGenPasses->doFinalization();
  delete codeGenPasses;

  return false; // success
}

/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging
/// LTO problems.
void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) {
  for (std::pair<StringRef, StringRef> o = getToken(options);
       !o.first.empty(); o = getToken(o.second)) {
    // ParseCommandLineOptions() expects argv[0] to be program name. Lazily add
    // that.
    if ( _codegenOptions.empty() )
      _codegenOptions.push_back(strdup("libLTO"));
    _codegenOptions.push_back(strdup(o.first.str().c_str()));
  }
}
<|endoftext|>


<commit_before>// Copyright 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/logging.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

#include <iomanip>

#include "base/safe_strerror_posix.h"

#if defined(OS_MACOSX)
#include <mach/mach.h>
#include "base/mac/scoped_mach_port.h"
#elif defined(OS_LINUX)
#include <sys/syscall.h>
#include <sys/types.h>
#endif

namespace logging {

namespace {

const char* const log_severity_names[] = {
  "INFO",
  "WARNING",
  "ERROR",
  "ERROR_REPORT",
  "FATAL"
};

}  // namespace

LogMessage::LogMessage(const char* function,
                       const char* file_path,
                       int line,
                       LogSeverity severity)
    : severity_(severity) {
  Init(function, file_path, line);
}

LogMessage::LogMessage(const char* function,
                       const char* file_path,
                       int line,
                       std::string* result)
    : severity_(LOG_FATAL) {
  Init(function, file_path, line);
  stream_ << "Check failed: " << *result << ". ";
  delete result;
}

LogMessage::~LogMessage() {
  stream_ << std::endl;
  std::string str_newline(stream_.str());
  fprintf(stderr, "%s", str_newline.c_str());
  fflush(stderr);
  if (severity_ == LOG_FATAL) {
#ifndef NDEBUG
    abort();
#else
    __asm__("int3");
#endif
  }
}

void LogMessage::Init(const char* function,
                      const std::string& file_path,
                      int line) {
  std::string file_name;
  size_t last_slash = file_path.find_last_of('/');
  if (last_slash != std::string::npos) {
    file_name.assign(file_path.substr(last_slash + 1));
  } else {
    file_name.assign(file_path);
  }

  pid_t pid = getpid();
#if defined(OS_MACOSX)
  base::mac::ScopedMachPort thread(mach_thread_self());
#elif defined(OS_LINUX)
  pid_t thread = syscall(__NR_gettid);
#endif

  struct timeval tv;
  gettimeofday(&tv, NULL);
  struct tm local_time;
  localtime_r(&tv.tv_sec, &local_time);

  stream_ << '['
          << pid
          << ':'
          << thread
          << ':'
          << std::setfill('0')
          << std::setw(4) << local_time.tm_year + 1900
          << std::setw(2) << local_time.tm_mon + 1
          << std::setw(2) << local_time.tm_mday
          << ','
          << std::setw(2) << local_time.tm_hour
          << std::setw(2) << local_time.tm_min
          << std::setw(2) << local_time.tm_sec
          << '.'
          << std::setw(6) << tv.tv_usec
          << ':';

  if (severity_ >= 0) {
    stream_ << log_severity_names[severity_];
  } else {
    stream_ << "VERBOSE" << -severity_;
  }

  stream_ << ' '
          << file_name
          << ':'
          << line
          << "] ";
}

ErrnoLogMessage::ErrnoLogMessage(const char* function,
                                 const char* file_path,
                                 int line,
                                 LogSeverity severity,
                                 int err)
    : LogMessage(function, file_path, line, severity),
      err_(err) {
}

ErrnoLogMessage::~ErrnoLogMessage() {
  stream() << ": "
           << safe_strerror(err_)
           << " ("
           << err_
           << ")";
}

}  // namespace logging
<commit_msg>Change mac logging.cc from mach_thread_self() to pthread_mach_thread_np(pthread_self()) to avoid needing to manage the Mach port reference.<commit_after>// Copyright 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/logging.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

#include <iomanip>

#include "base/safe_strerror_posix.h"

#if defined(OS_MACOSX)
#include <mach/mach.h>
#elif defined(OS_LINUX)
#include <sys/syscall.h>
#include <sys/types.h>
#endif

namespace logging {

namespace {

const char* const log_severity_names[] = {
  "INFO",
  "WARNING",
  "ERROR",
  "ERROR_REPORT",
  "FATAL"
};

}  // namespace

LogMessage::LogMessage(const char* function,
                       const char* file_path,
                       int line,
                       LogSeverity severity)
    : severity_(severity) {
  Init(function, file_path, line);
}

LogMessage::LogMessage(const char* function,
                       const char* file_path,
                       int line,
                       std::string* result)
    : severity_(LOG_FATAL) {
  Init(function, file_path, line);
  stream_ << "Check failed: " << *result << ". ";
  delete result;
}

LogMessage::~LogMessage() {
  stream_ << std::endl;
  std::string str_newline(stream_.str());
  fprintf(stderr, "%s", str_newline.c_str());
  fflush(stderr);
  if (severity_ == LOG_FATAL) {
#ifndef NDEBUG
    abort();
#else
    __asm__("int3");
#endif
  }
}

void LogMessage::Init(const char* function,
                      const std::string& file_path,
                      int line) {
  std::string file_name;
  size_t last_slash = file_path.find_last_of('/');
  if (last_slash != std::string::npos) {
    file_name.assign(file_path.substr(last_slash + 1));
  } else {
    file_name.assign(file_path);
  }

  pid_t pid = getpid();
#if defined(OS_MACOSX)
  mach_port_t thread = pthread_mach_thread_np(pthread_self());
#elif defined(OS_LINUX)
  pid_t thread = syscall(__NR_gettid);
#endif

  struct timeval tv;
  gettimeofday(&tv, NULL);
  struct tm local_time;
  localtime_r(&tv.tv_sec, &local_time);

  stream_ << '['
          << pid
          << ':'
          << thread
          << ':'
          << std::setfill('0')
          << std::setw(4) << local_time.tm_year + 1900
          << std::setw(2) << local_time.tm_mon + 1
          << std::setw(2) << local_time.tm_mday
          << ','
          << std::setw(2) << local_time.tm_hour
          << std::setw(2) << local_time.tm_min
          << std::setw(2) << local_time.tm_sec
          << '.'
          << std::setw(6) << tv.tv_usec
          << ':';

  if (severity_ >= 0) {
    stream_ << log_severity_names[severity_];
  } else {
    stream_ << "VERBOSE" << -severity_;
  }

  stream_ << ' '
          << file_name
          << ':'
          << line
          << "] ";
}

ErrnoLogMessage::ErrnoLogMessage(const char* function,
                                 const char* file_path,
                                 int line,
                                 LogSeverity severity,
                                 int err)
    : LogMessage(function, file_path, line, severity),
      err_(err) {
}

ErrnoLogMessage::~ErrnoLogMessage() {
  stream() << ": "
           << safe_strerror(err_)
           << " ("
           << err_
           << ")";
}

}  // namespace logging
<|endoftext|>


<commit_before>// Time:  O(nlogn)
// Space: O(n)

// Divide and Conquer.
class Solution {
public:
    enum {start, end, height};

    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        const auto intervals = move(ComputeSkylineInInterval(buildings, 0, buildings.size()));

        vector<pair<int, int>> res;
        int last_end = -1;
        for (const auto& interval : intervals) {
            if (last_end != -1 && last_end < interval[start]) {
                res.emplace_back(last_end, 0);
            }
            res.emplace_back(interval[start], interval[height]);
            last_end = interval[end];
        }
        if (last_end != -1) {
            res.emplace_back(last_end, 0);
        }
        return res;
    }

    // Divide and Conquer.
    vector<vector<int>> ComputeSkylineInInterval(const vector<vector<int>>& buildings,
                                                 int left_endpoint, int right_endpoint) {
        if (right_endpoint - left_endpoint <= 1) {  // 0 or 1 skyline, just copy it.
            return {buildings.cbegin() + left_endpoint,
                    buildings.cbegin() + right_endpoint};
        }
        int mid = left_endpoint + ((right_endpoint - left_endpoint) / 2);
        auto left_skyline = move(ComputeSkylineInInterval(buildings, left_endpoint, mid));
        auto right_skyline = move(ComputeSkylineInInterval(buildings, mid, right_endpoint));
        return MergeSkylines(left_skyline, right_skyline);
    }

    // Merge Sort
    vector<vector<int>> MergeSkylines(vector<vector<int>>& left_skyline, vector<vector<int>>& right_skyline) {
        int i = 0, j = 0;
        vector<vector<int>> merged;

        while (i < left_skyline.size() && j < right_skyline.size()) {
            if (left_skyline[i][end] < right_skyline[j][start]) {
                merged.emplace_back(move(left_skyline[i++]));
            } else if (right_skyline[j][end] < left_skyline[i][start]) {
                merged.emplace_back(move(right_skyline[j++]));
            } else if (left_skyline[i][start] <= right_skyline[j][start]) {
                MergeIntersectSkylines(merged, left_skyline[i], i,
                                       right_skyline[j], j);
            } else {  // left_skyline[i][start] > right_skyline[j][start].
                MergeIntersectSkylines(merged, right_skyline[j], j,
                                       left_skyline[i], i);
            }
        }

        // Insert the remaining skylines.
        merged.insert(merged.end(), left_skyline.begin() + i, left_skyline.end());
        merged.insert(merged.end(), right_skyline.begin() + j, right_skyline.end());
        return merged;
    }

    // a[start] <= b[start]
    void MergeIntersectSkylines(vector<vector<int>>& merged, vector<int>& a, int& a_idx,
                                vector<int>& b, int& b_idx) {
        if (a[end] <= b[end]) {
            if (a[height] > b[height]) {  // |aaa|
                if (b[end] != a[end]) {   // |abb|b
                    b[start] = a[end];
                    merged.emplace_back(move(a)), ++a_idx;
                } else {        // aaa
                    ++b_idx;    // abb
                }
            } else if (a[height] == b[height]) { // abb
                b[start] = a[start], ++a_idx;    // abb
            } else {  // a[height] < b[height].
                if (a[start] != b[start]) {                                           //    bb
                    merged.emplace_back(move(vector<int>{a[start], b[start], a[height]}));  // |a|bb
                }
                ++a_idx;
            }
        } else {  // a[end] > b[end].
            if (a[height] >= b[height]) {  // aaaa
                ++b_idx;                   // abba
            } else {
                //    |bb|
                // |a||bb|a
                if (a[start] != b[start]) {
                    merged.emplace_back(move(vector<int>{a[start], b[start], a[height]}));
                }
                a[start] = b[end];
                merged.emplace_back(move(b)), ++b_idx;
            }
        }
    }
};

// Time:  O(nlogn)
// Space: O(n)
// BST Solution.
class Solution2 {
public:
    vector<pair<int, int> > getSkyline(vector<vector<int> >& buildings) {
        unordered_map<int, vector<int>> start_point_to_heights;
        unordered_map<int, vector<int>> end_point_to_heights;
        set<int> points;

        for (int i = 0; i < buildings.size(); ++i) {
            start_point_to_heights[buildings[i][0]].push_back(buildings[i][2]);
            end_point_to_heights[buildings[i][1]].push_back(buildings[i][2]);
            points.emplace(buildings[i][0]);
            points.emplace(buildings[i][1]);
        }

        vector<pair<int, int>> res;
        map<int, int> height_to_count;
        int curr_max = 0;
        // Enumerate each point in increasing order.
        for (auto it = points.begin(); it != points.end(); ++it) {
            vector<int> start_point_heights = start_point_to_heights[*it];
            vector<int> end_point_heights = end_point_to_heights[*it];

            for (int i = 0; i < start_point_heights.size(); ++i) {
                ++height_to_count[start_point_heights[i]];
            }

            for (int i = 0; i < end_point_heights.size(); ++i) {
                --height_to_count[end_point_heights[i]];
                if (height_to_count[end_point_heights[i]] == 0) {
                    height_to_count.erase(end_point_heights[i]);
                }
            }

            if (height_to_count.empty() || curr_max != height_to_count.rbegin()->first) {
                curr_max = height_to_count.empty() ? 0 : height_to_count.rbegin()->first;
                res.emplace_back(*it, curr_max);
            }
        }
        return res;
    }
};
<commit_msg>Update the-skyline-problem.cpp<commit_after>// Time:  O(nlogn)
// Space: O(n)

// BST solution.
class Solution {
public:
    vector<pair<int, int> > getSkyline(vector<vector<int> >& buildings) {
        unordered_map<int, vector<int>> start_point_to_heights;
        unordered_map<int, vector<int>> end_point_to_heights;
        set<int> points;

        for (int i = 0; i < buildings.size(); ++i) {
            start_point_to_heights[buildings[i][0]].push_back(buildings[i][2]);
            end_point_to_heights[buildings[i][1]].push_back(buildings[i][2]);
            points.emplace(buildings[i][0]);
            points.emplace(buildings[i][1]);
        }

        vector<pair<int, int>> res;
        map<int, int> height_to_count;
        int curr_max = 0;
        // Enumerate each point in increasing order.
        for (auto it = points.begin(); it != points.end(); ++it) {
            vector<int> start_point_heights = start_point_to_heights[*it];
            vector<int> end_point_heights = end_point_to_heights[*it];

            for (int i = 0; i < start_point_heights.size(); ++i) {
                ++height_to_count[start_point_heights[i]];
            }

            for (int i = 0; i < end_point_heights.size(); ++i) {
                --height_to_count[end_point_heights[i]];
                if (height_to_count[end_point_heights[i]] == 0) {
                    height_to_count.erase(end_point_heights[i]);
                }
            }

            if (height_to_count.empty() || curr_max != height_to_count.rbegin()->first) {
                curr_max = height_to_count.empty() ? 0 : height_to_count.rbegin()->first;
                res.emplace_back(*it, curr_max);
            }
        }
        return res;
    }
};

// Time:  O(nlogn)
// Space: O(n)
// Divide and conquer solution.
class Solution {
public:
    enum {start, end, height};

    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        const auto intervals = move(ComputeSkylineInInterval(buildings, 0, buildings.size()));

        vector<pair<int, int>> res;
        int last_end = -1;
        for (const auto& interval : intervals) {
            if (last_end != -1 && last_end < interval[start]) {
                res.emplace_back(last_end, 0);
            }
            res.emplace_back(interval[start], interval[height]);
            last_end = interval[end];
        }
        if (last_end != -1) {
            res.emplace_back(last_end, 0);
        }
        return res;
    }

    // Divide and Conquer.
    vector<vector<int>> ComputeSkylineInInterval(const vector<vector<int>>& buildings,
                                                 int left_endpoint, int right_endpoint) {
        if (right_endpoint - left_endpoint <= 1) {  // 0 or 1 skyline, just copy it.
            return {buildings.cbegin() + left_endpoint,
                    buildings.cbegin() + right_endpoint};
        }
        int mid = left_endpoint + ((right_endpoint - left_endpoint) / 2);
        auto left_skyline = move(ComputeSkylineInInterval(buildings, left_endpoint, mid));
        auto right_skyline = move(ComputeSkylineInInterval(buildings, mid, right_endpoint));
        return MergeSkylines(left_skyline, right_skyline);
    }

    // Merge Sort
    vector<vector<int>> MergeSkylines(vector<vector<int>>& left_skyline, vector<vector<int>>& right_skyline) {
        int i = 0, j = 0;
        vector<vector<int>> merged;

        while (i < left_skyline.size() && j < right_skyline.size()) {
            if (left_skyline[i][end] < right_skyline[j][start]) {
                merged.emplace_back(move(left_skyline[i++]));
            } else if (right_skyline[j][end] < left_skyline[i][start]) {
                merged.emplace_back(move(right_skyline[j++]));
            } else if (left_skyline[i][start] <= right_skyline[j][start]) {
                MergeIntersectSkylines(merged, left_skyline[i], i,
                                       right_skyline[j], j);
            } else {  // left_skyline[i][start] > right_skyline[j][start].
                MergeIntersectSkylines(merged, right_skyline[j], j,
                                       left_skyline[i], i);
            }
        }

        // Insert the remaining skylines.
        merged.insert(merged.end(), left_skyline.begin() + i, left_skyline.end());
        merged.insert(merged.end(), right_skyline.begin() + j, right_skyline.end());
        return merged;
    }

    // a[start] <= b[start]
    void MergeIntersectSkylines(vector<vector<int>>& merged, vector<int>& a, int& a_idx,
                                vector<int>& b, int& b_idx) {
        if (a[end] <= b[end]) {
            if (a[height] > b[height]) {  // |aaa|
                if (b[end] != a[end]) {   // |abb|b
                    b[start] = a[end];
                    merged.emplace_back(move(a)), ++a_idx;
                } else {        // aaa
                    ++b_idx;    // abb
                }
            } else if (a[height] == b[height]) { // abb
                b[start] = a[start], ++a_idx;    // abb
            } else {  // a[height] < b[height].
                if (a[start] != b[start]) {                                           //    bb
                    merged.emplace_back(move(vector<int>{a[start], b[start], a[height]}));  // |a|bb
                }
                ++a_idx;
            }
        } else {  // a[end] > b[end].
            if (a[height] >= b[height]) {  // aaaa
                ++b_idx;                   // abba
            } else {
                //    |bb|
                // |a||bb|a
                if (a[start] != b[start]) {
                    merged.emplace_back(move(vector<int>{a[start], b[start], a[height]}));
                }
                a[start] = b[end];
                merged.emplace_back(move(b)), ++b_idx;
            }
        }
    }
};
<|endoftext|>


<commit_before>/*
    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

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

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qeventloop.h>
#include <qhbox.h>
#include <qlayout.h>
#include <qpixmap.h>

#include <dcopclient.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kurllabel.h>
#include <kcharsets.h>

#include "summarywidget.h"

SummaryWidget::SummaryWidget( QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ),
    DCOPObject( "NewsTickerPlugin" ), mLayout( 0 )
{
  QVBoxLayout *vlay = new QVBoxLayout( this, 3, 3 );

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kontact_news",
                                                  KIcon::Desktop, KIcon::SizeMedium );

  QWidget *header = createHeader( this, icon, i18n( "News Feeds" ) );
  vlay->addWidget( header );

  QString error;
  QCString appID;

  bool dcopAvailable = true;
  if ( !kapp->dcopClient()->isApplicationRegistered( "rssservice" ) ) {
    if ( KApplication::startServiceByDesktopName( "rssservice", QStringList(), &error, &appID ) ) {
      QLabel *label = new QLabel( i18n( "No rss dcop service available.\nYou need rssservice to use this plugin." ), this );
      vlay->addWidget( label, Qt::AlignHCenter );
      dcopAvailable = false;
    }
  }

  mBaseWidget = new QWidget( this, "baseWidget" );
  vlay->addWidget( mBaseWidget );

  connect( &mTimer, SIGNAL( timeout() ), this, SLOT( updateDocuments() ) );

  readConfig();

  if ( dcopAvailable )
    initDocuments();

  connectDCOPSignal( 0, 0, "added(QString)", "documentAdded(QString)", false );
  connectDCOPSignal( 0, 0, "removed(QString)", "documentRemoved(QString)", false );
}

int SummaryWidget::summaryHight() const
{
  return ( mFeeds.count() == 0 ? 1 : mFeeds.count() );
}

void SummaryWidget::documentAdded( QString )
{
  initDocuments();
}

void SummaryWidget::documentRemoved( QString )
{
  initDocuments();
}

void SummaryWidget::configChanged()
{
  readConfig();

  updateView();
}

void SummaryWidget::readConfig()
{
  KConfig config( "kcmkontactkntrc" );
  config.setGroup( "General" );

  mUpdateInterval = config.readNumEntry( "UpdateInterval", 600 );
  mArticleCount = config.readNumEntry( "ArticleCount", 4 );
}

void SummaryWidget::initDocuments()
{
  mFeeds.clear();

  DCOPRef dcopCall( "rssservice", "RSSService" );
  QStringList urls;
  dcopCall.call( "list()" ).get( urls );

  if ( urls.isEmpty() ) { // add default
    urls.append( "http://www.kde.org/dotkdeorg.rdf" );
    dcopCall.send( "add(QString)", urls[ 0 ] );
  }

  QStringList::Iterator it;
  for ( it = urls.begin(); it != urls.end(); ++it ) {
    DCOPRef feedRef = dcopCall.call( "document(QString)", *it );

    Feed feed;
    feed.ref = feedRef;
    feedRef.call( "title()" ).get( feed.title );
    feedRef.call( "link()" ).get( feed.url );
    feedRef.call( "pixmap()" ).get( feed.logo );
    mFeeds.append( feed );

    connectDCOPSignal( "rssservice", feedRef.obj(), "documentUpdated(DCOPRef)",
                       "documentUpdated(DCOPRef)", false );

    qApp->processEvents( QEventLoop::ExcludeUserInput |
                         QEventLoop::ExcludeSocketNotifiers );
  }

  updateDocuments();
}

void SummaryWidget::updateDocuments()
{
  mTimer.stop();

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
    (*it).ref.send( "refresh()" );

  mTimer.start( 1000 * mUpdateInterval );
}

void SummaryWidget::documentUpdated( DCOPRef feedRef )
{
  static uint feedCounter = 0;
  ArticleMap map;

  int numArticles = feedRef.call( "count()" );
  for ( int i = 0; i < numArticles; ++i ) {
    DCOPRef artRef = feedRef.call( "article(int)", i );
    QString title, url;

    qApp->processEvents( QEventLoop::ExcludeUserInput |
                         QEventLoop::ExcludeSocketNotifiers );

    artRef.call( "title()" ).get( title );
    artRef.call( "link()" ).get( url );

    QPair<QString, KURL> article(title, KURL( url ));
    map.append( article );
  }

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
    if ( (*it).ref.obj() == feedRef.obj() ) {
      (*it).map = map;
      if ( (*it).title.isEmpty() )
        feedRef.call( "title()" ).get( (*it).title );
      if ( (*it).url.isEmpty() )
        feedRef.call( "link()" ).get( (*it).url );
      if ( (*it).logo.isNull() )
        feedRef.call( "pixmap()" ).get( (*it).logo );
    }

  feedCounter++;
  if ( feedCounter == mFeeds.count() ) {
    feedCounter = 0;
    updateView();
  }
}

void SummaryWidget::updateView()
{
  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  delete mLayout;
  mLayout = new QVBoxLayout( mBaseWidget, 3 );

  QFont boldFont;
  boldFont.setBold( true );
  boldFont.setPointSize( boldFont.pointSize() + 2 );

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
    QHBox *hbox = new QHBox( mBaseWidget );
    mLayout->addWidget( hbox );

    // icon
    KURLLabel *urlLabel = new KURLLabel( hbox );
    urlLabel->setURL( (*it).url );
    urlLabel->setPixmap( (*it).logo );
    urlLabel->setMaximumSize( urlLabel->minimumSizeHint() );
    mLabels.append( urlLabel );

    connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
             kapp, SLOT( invokeBrowser( const QString& ) ) );

    // header
    QLabel *label = new QLabel( hbox );
    label->setText( KCharsets::resolveEntities( (*it).title ) );
    label->setAlignment( AlignLeft|AlignVCenter );
    label->setFont( boldFont );
    label->setIndent( 6 );
    label->setMaximumSize( label->minimumSizeHint() );
    mLabels.append( label );

    hbox->setMaximumWidth( hbox->minimumSizeHint().width() );
    hbox->show();

    // articles
    ArticleMap articles = (*it).map;
    ArticleMap::Iterator artIt;
    int numArticles = 0;
    for ( artIt = articles.begin(); artIt != articles.end() && numArticles < mArticleCount; ++artIt ) {
      urlLabel = new KURLLabel( (*artIt).second.url(), (*artIt).first, mBaseWidget );
      urlLabel->setMaximumSize( urlLabel->minimumSizeHint() );
      mLabels.append( urlLabel );
      mLayout->addWidget( urlLabel );

      connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
               kapp, SLOT( invokeBrowser( const QString& ) ) );

      numArticles++;
    }
  }

  for ( QLabel *label = mLabels.first(); label; label = mLabels.next() )
    label->show();
}

QStringList SummaryWidget::configModules() const
{
  return "kcmkontactknt.desktop";
}

#include "summarywidget.moc"
<commit_msg>Make the newsticker wrap and make it possible to avoid horizontal scrollbars. Approved by: danimo<commit_after>/*
    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

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

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qeventloop.h>
#include <qhbox.h>
#include <qlayout.h>
#include <qpixmap.h>

#include <dcopclient.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kurllabel.h>
#include <kcharsets.h>

#include "summarywidget.h"

SummaryWidget::SummaryWidget( QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ),
    DCOPObject( "NewsTickerPlugin" ), mLayout( 0 )
{
  QVBoxLayout *vlay = new QVBoxLayout( this, 3, 3 );

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kontact_news",
                                                  KIcon::Desktop, KIcon::SizeMedium );

  QWidget *header = createHeader( this, icon, i18n( "News Feeds" ) );
  vlay->addWidget( header );

  QString error;
  QCString appID;

  bool dcopAvailable = true;
  if ( !kapp->dcopClient()->isApplicationRegistered( "rssservice" ) ) {
    if ( KApplication::startServiceByDesktopName( "rssservice", QStringList(), &error, &appID ) ) {
      QLabel *label = new QLabel( i18n( "No rss dcop service available.\nYou need rssservice to use this plugin." ), this );
      vlay->addWidget( label, Qt::AlignHCenter );
      dcopAvailable = false;
    }
  }

  mBaseWidget = new QWidget( this, "baseWidget" );
  vlay->addWidget( mBaseWidget );

  connect( &mTimer, SIGNAL( timeout() ), this, SLOT( updateDocuments() ) );

  readConfig();

  if ( dcopAvailable )
    initDocuments();

  connectDCOPSignal( 0, 0, "added(QString)", "documentAdded(QString)", false );
  connectDCOPSignal( 0, 0, "removed(QString)", "documentRemoved(QString)", false );
}

int SummaryWidget::summaryHight() const
{
  return ( mFeeds.count() == 0 ? 1 : mFeeds.count() );
}

void SummaryWidget::documentAdded( QString )
{
  initDocuments();
}

void SummaryWidget::documentRemoved( QString )
{
  initDocuments();
}

void SummaryWidget::configChanged()
{
  readConfig();

  updateView();
}

void SummaryWidget::readConfig()
{
  KConfig config( "kcmkontactkntrc" );
  config.setGroup( "General" );

  mUpdateInterval = config.readNumEntry( "UpdateInterval", 600 );
  mArticleCount = config.readNumEntry( "ArticleCount", 4 );
}

void SummaryWidget::initDocuments()
{
  mFeeds.clear();

  DCOPRef dcopCall( "rssservice", "RSSService" );
  QStringList urls;
  dcopCall.call( "list()" ).get( urls );

  if ( urls.isEmpty() ) { // add default
    urls.append( "http://www.kde.org/dotkdeorg.rdf" );
    dcopCall.send( "add(QString)", urls[ 0 ] );
  }

  QStringList::Iterator it;
  for ( it = urls.begin(); it != urls.end(); ++it ) {
    DCOPRef feedRef = dcopCall.call( "document(QString)", *it );

    Feed feed;
    feed.ref = feedRef;
    feedRef.call( "title()" ).get( feed.title );
    feedRef.call( "link()" ).get( feed.url );
    feedRef.call( "pixmap()" ).get( feed.logo );
    mFeeds.append( feed );

    connectDCOPSignal( "rssservice", feedRef.obj(), "documentUpdated(DCOPRef)",
                       "documentUpdated(DCOPRef)", false );

    qApp->processEvents( QEventLoop::ExcludeUserInput |
                         QEventLoop::ExcludeSocketNotifiers );
  }

  updateDocuments();
}

void SummaryWidget::updateDocuments()
{
  mTimer.stop();

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
    (*it).ref.send( "refresh()" );

  mTimer.start( 1000 * mUpdateInterval );
}

void SummaryWidget::documentUpdated( DCOPRef feedRef )
{
  static uint feedCounter = 0;
  ArticleMap map;

  int numArticles = feedRef.call( "count()" );
  for ( int i = 0; i < numArticles; ++i ) {
    DCOPRef artRef = feedRef.call( "article(int)", i );
    QString title, url;

    qApp->processEvents( QEventLoop::ExcludeUserInput |
                         QEventLoop::ExcludeSocketNotifiers );

    artRef.call( "title()" ).get( title );
    artRef.call( "link()" ).get( url );

    QPair<QString, KURL> article(title, KURL( url ));
    map.append( article );
  }

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it )
    if ( (*it).ref.obj() == feedRef.obj() ) {
      (*it).map = map;
      if ( (*it).title.isEmpty() )
        feedRef.call( "title()" ).get( (*it).title );
      if ( (*it).url.isEmpty() )
        feedRef.call( "link()" ).get( (*it).url );
      if ( (*it).logo.isNull() )
        feedRef.call( "pixmap()" ).get( (*it).logo );
    }

  feedCounter++;
  if ( feedCounter == mFeeds.count() ) {
    feedCounter = 0;
    updateView();
  }
}

void SummaryWidget::updateView()
{
  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  delete mLayout;
  mLayout = new QVBoxLayout( mBaseWidget, 3 );

  QFont boldFont;
  boldFont.setBold( true );
  boldFont.setPointSize( boldFont.pointSize() + 2 );

  FeedList::Iterator it;
  for ( it = mFeeds.begin(); it != mFeeds.end(); ++it ) {
    QHBox *hbox = new QHBox( mBaseWidget );
    mLayout->addWidget( hbox );

    // icon
    KURLLabel *urlLabel = new KURLLabel( hbox );
    urlLabel->setURL( (*it).url );
    urlLabel->setPixmap( (*it).logo );
    urlLabel->setMaximumSize( urlLabel->minimumSizeHint() );
    mLabels.append( urlLabel );

    connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
             kapp, SLOT( invokeBrowser( const QString& ) ) );

    // header
    QLabel *label = new QLabel( hbox );
    label->setText( KCharsets::resolveEntities( (*it).title ) );
    label->setAlignment( AlignLeft|AlignVCenter );
    label->setFont( boldFont );
    label->setIndent( 6 );
    label->setMaximumSize( label->minimumSizeHint() );
    mLabels.append( label );

    hbox->setMaximumWidth( hbox->minimumSizeHint().width() );
    hbox->show();

    // articles
    ArticleMap articles = (*it).map;
    ArticleMap::Iterator artIt;
    int numArticles = 0;
    for ( artIt = articles.begin(); artIt != articles.end() && numArticles < mArticleCount; ++artIt ) {
      urlLabel = new KURLLabel( (*artIt).second.url(), (*artIt).first, mBaseWidget );
      urlLabel->setTextFormat( RichText );
      mLabels.append( urlLabel );
      mLayout->addWidget( urlLabel );

      connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
               kapp, SLOT( invokeBrowser( const QString& ) ) );

      numArticles++;
    }
  }

  for ( QLabel *label = mLabels.first(); label; label = mLabels.next() )
    label->show();
}

QStringList SummaryWidget::configModules() const
{
  return "kcmkontactknt.desktop";
}

#include "summarywidget.moc"
<|endoftext|>


<commit_before>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <assert.h>
#include <float.h>
#include <string.h>

// This work is based on:
// Nicolas Capens. Advanced Rasterization. 2004
namespace meshopt
{

const int kViewport = 256;

struct OverdrawBuffer
{
	float z[kViewport][kViewport][2];
	unsigned int overdraw[kViewport][kViewport][2];
};

template <typename T>
static T min(T a, T b)
{
	return a < b ? a : b;
}

template <typename T>
static T max(T a, T b)
{
	return a > b ? a : b;
}

static float det2x2(float a, float b, float c, float d)
{
	// (a b)
	// (c d)
	return a * d - b * c;
}

static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
{
	// z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
	// z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
	// (x2-x1 y2-y1)(dzdx) = (z2-z1)
	// (x3-x1 y3-y1)(dzdy)   (z3-z1)
	// we'll solve it with Cramer's rule
	float det = det2x2(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
	float invdet = (det == 0) ? 0 : 1 / det;

	dzdx = det2x2(z2 - z1, y2 - y1, z3 - z1, y3 - y1) * invdet;
	dzdy = det2x2(x2 - x1, z2 - z1, x3 - x1, z3 - z1) * invdet;

	return det;
}

// half-space fixed point triangle rasterizer
static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z)
{
	// compute depth gradients
	float DZx, DZy;
	float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
	int sign = det > 0;

	// flip backfacing triangles to simplify rasterization logic
	if (sign)
	{
		// flipping v2 & v3 preserves depth gradients since they're based on v1
		float t;
		t = v2x, v2x = v3x, v3x = t;
		t = v2y, v2y = v3y, v3y = t;
		t = v2z, v2z = v3z, v3z = t;

		// flip depth since we rasterize backfacing triangles to second buffer with reverse Z; only v1z is used below
		v1z = kViewport - v1z;
		DZx = -DZx;
		DZy = -DZy;
	}

	// coordinates, 28.4 fixed point
	int X1 = int(16.0f * v1x + 0.5f);
	int X2 = int(16.0f * v2x + 0.5f);
	int X3 = int(16.0f * v3x + 0.5f);

	int Y1 = int(16.0f * v1y + 0.5f);
	int Y2 = int(16.0f * v2y + 0.5f);
	int Y3 = int(16.0f * v3y + 0.5f);

	// bounding rectangle, clipped against viewport
	// since we rasterize pixels with covered centers, min >0.5 should round up
	// as for max, due to top-left filling convention we will never rasterize right/bottom edges
	// so max >= 0.5 should round down
	int minx = max((min(X1, min(X2, X3)) + 7) >> 4, 0);
	int maxx = min((max(X1, max(X2, X3)) + 7) >> 4, kViewport);
	int miny = max((min(Y1, min(Y2, Y3)) + 7) >> 4, 0);
	int maxy = min((max(Y1, max(Y2, Y3)) + 7) >> 4, kViewport);

	// deltas, 28.4 fixed point
	int DX12 = X1 - X2;
	int DX23 = X2 - X3;
	int DX31 = X3 - X1;

	int DY12 = Y1 - Y2;
	int DY23 = Y2 - Y3;
	int DY31 = Y3 - Y1;

	// fill convention correction
	int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0);
	int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0);
	int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0);

	// half edge equations, 24.8 fixed point
	// note that we offset minx/miny by half pixel since we want to rasterize pixels with covered centers
	int FX = (minx << 4) + 8;
	int FY = (miny << 4) + 8;
	int CY1 = DX12 * (FY - Y1) - DY12 * (FX - X1) + TL1 - 1;
	int CY2 = DX23 * (FY - Y2) - DY23 * (FX - X2) + TL2 - 1;
	int CY3 = DX31 * (FY - Y3) - DY31 * (FX - X3) + TL3 - 1;
	float ZY = v1z + (DZx * float(FX - X1) + DZy * float(FY - Y1)) * (1 / 16.f);

	for (int y = miny; y < maxy; y++)
	{
		int CX1 = CY1;
		int CX2 = CY2;
		int CX3 = CY3;
		float ZX = ZY;

		for (int x = minx; x < maxx; x++)
		{
			// check if all CXn are non-negative
			if ((CX1 | CX2 | CX3) >= 0)
			{
				if (ZX >= buffer->z[y][x][sign])
				{
					buffer->z[y][x][sign] = ZX;
					buffer->overdraw[y][x][sign]++;
				}
			}

			// signed left shift is UB for negative numbers so use unsigned-signed casts
			CX1 -= int(unsigned(DY12) << 4);
			CX2 -= int(unsigned(DY23) << 4);
			CX3 -= int(unsigned(DY31) << 4);
			ZX += DZx;
		}

		// signed left shift is UB for negative numbers so use unsigned-signed casts
		CY1 += int(unsigned(DX12) << 4);
		CY2 += int(unsigned(DX23) << 4);
		CY3 += int(unsigned(DX31) << 4);
		ZY += DZy;
	}
}

} // namespace meshopt

meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	using namespace meshopt;

	assert(index_count % 3 == 0);
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	meshopt_Allocator allocator;

	size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

	meshopt_OverdrawStatistics result = {};

	float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
	float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};

	for (size_t i = 0; i < vertex_count; ++i)
	{
		const float* v = vertex_positions + i * vertex_stride_float;

		for (int j = 0; j < 3; ++j)
		{
			minv[j] = min(minv[j], v[j]);
			maxv[j] = max(maxv[j], v[j]);
		}
	}

	float extent = max(maxv[0] - minv[0], max(maxv[1] - minv[1], maxv[2] - minv[2]));
	float scale = kViewport / extent;

	float* triangles = allocator.allocate<float>(index_count * 3);

	for (size_t i = 0; i < index_count; ++i)
	{
		unsigned int index = indices[i];
		assert(index < vertex_count);

		const float* v = vertex_positions + index * vertex_stride_float;

		triangles[i * 3 + 0] = (v[0] - minv[0]) * scale;
		triangles[i * 3 + 1] = (v[1] - minv[1]) * scale;
		triangles[i * 3 + 2] = (v[2] - minv[2]) * scale;
	}

	OverdrawBuffer* buffer = allocator.allocate<OverdrawBuffer>(1);

	for (int axis = 0; axis < 3; ++axis)
	{
		memset(buffer, 0, sizeof(OverdrawBuffer));

		for (size_t i = 0; i < index_count; i += 3)
		{
			const float* vn0 = &triangles[3 * (i + 0)];
			const float* vn1 = &triangles[3 * (i + 1)];
			const float* vn2 = &triangles[3 * (i + 2)];

			switch (axis)
			{
			case 0:
				rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]);
				break;
			case 1:
				rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]);
				break;
			case 2:
				rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]);
				break;
			}
		}

		for (int y = 0; y < kViewport; ++y)
			for (int x = 0; x < kViewport; ++x)
				for (int s = 0; s < 2; ++s)
				{
					unsigned int overdraw = buffer->overdraw[y][x][s];

					result.pixels_covered += overdraw > 0;
					result.pixels_shaded += overdraw;
				}
	}

	result.overdraw = result.pixels_covered ? float(result.pixels_shaded) / float(result.pixels_covered) : 0.f;

	return result;
}
<commit_msg>overdraw: Optimize rasterizer in Debug<commit_after>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <assert.h>
#include <float.h>
#include <string.h>

// This work is based on:
// Nicolas Capens. Advanced Rasterization. 2004
namespace meshopt
{

const int kViewport = 256;

struct OverdrawBuffer
{
	float z[kViewport][kViewport][2];
	unsigned int overdraw[kViewport][kViewport][2];
};

#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif

#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif

static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
{
	// z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
	// z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
	// (x2-x1 y2-y1)(dzdx) = (z2-z1)
	// (x3-x1 y3-y1)(dzdy)   (z3-z1)
	// we'll solve it with Cramer's rule
	float det = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
	float invdet = (det == 0) ? 0 : 1 / det;

	dzdx = (z2 - z1) * (y3 - y1) - (y2 - y1) * (z3 - z1) * invdet;
	dzdy = (x2 - x1) * (z3 - z1) - (z2 - z1) * (x3 - x1) * invdet;

	return det;
}

// half-space fixed point triangle rasterizer
static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z)
{
	// compute depth gradients
	float DZx, DZy;
	float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
	int sign = det > 0;

	// flip backfacing triangles to simplify rasterization logic
	if (sign)
	{
		// flipping v2 & v3 preserves depth gradients since they're based on v1
		float t;
		t = v2x, v2x = v3x, v3x = t;
		t = v2y, v2y = v3y, v3y = t;
		t = v2z, v2z = v3z, v3z = t;

		// flip depth since we rasterize backfacing triangles to second buffer with reverse Z; only v1z is used below
		v1z = kViewport - v1z;
		DZx = -DZx;
		DZy = -DZy;
	}

	// coordinates, 28.4 fixed point
	int X1 = int(16.0f * v1x + 0.5f);
	int X2 = int(16.0f * v2x + 0.5f);
	int X3 = int(16.0f * v3x + 0.5f);

	int Y1 = int(16.0f * v1y + 0.5f);
	int Y2 = int(16.0f * v2y + 0.5f);
	int Y3 = int(16.0f * v3y + 0.5f);

	// bounding rectangle, clipped against viewport
	// since we rasterize pixels with covered centers, min >0.5 should round up
	// as for max, due to top-left filling convention we will never rasterize right/bottom edges
	// so max >= 0.5 should round down
	int minx = max((min(X1, min(X2, X3)) + 7) >> 4, 0);
	int maxx = min((max(X1, max(X2, X3)) + 7) >> 4, kViewport);
	int miny = max((min(Y1, min(Y2, Y3)) + 7) >> 4, 0);
	int maxy = min((max(Y1, max(Y2, Y3)) + 7) >> 4, kViewport);

	// deltas, 28.4 fixed point
	int DX12 = X1 - X2;
	int DX23 = X2 - X3;
	int DX31 = X3 - X1;

	int DY12 = Y1 - Y2;
	int DY23 = Y2 - Y3;
	int DY31 = Y3 - Y1;

	// fill convention correction
	int TL1 = DY12 < 0 || (DY12 == 0 && DX12 > 0);
	int TL2 = DY23 < 0 || (DY23 == 0 && DX23 > 0);
	int TL3 = DY31 < 0 || (DY31 == 0 && DX31 > 0);

	// half edge equations, 24.8 fixed point
	// note that we offset minx/miny by half pixel since we want to rasterize pixels with covered centers
	int FX = (minx << 4) + 8;
	int FY = (miny << 4) + 8;
	int CY1 = DX12 * (FY - Y1) - DY12 * (FX - X1) + TL1 - 1;
	int CY2 = DX23 * (FY - Y2) - DY23 * (FX - X2) + TL2 - 1;
	int CY3 = DX31 * (FY - Y3) - DY31 * (FX - X3) + TL3 - 1;
	float ZY = v1z + (DZx * float(FX - X1) + DZy * float(FY - Y1)) * (1 / 16.f);

	for (int y = miny; y < maxy; y++)
	{
		int CX1 = CY1;
		int CX2 = CY2;
		int CX3 = CY3;
		float ZX = ZY;

		for (int x = minx; x < maxx; x++)
		{
			// check if all CXn are non-negative
			if ((CX1 | CX2 | CX3) >= 0)
			{
				if (ZX >= buffer->z[y][x][sign])
				{
					buffer->z[y][x][sign] = ZX;
					buffer->overdraw[y][x][sign]++;
				}
			}

			// signed left shift is UB for negative numbers so use unsigned-signed casts
			CX1 -= int(unsigned(DY12) << 4);
			CX2 -= int(unsigned(DY23) << 4);
			CX3 -= int(unsigned(DY31) << 4);
			ZX += DZx;
		}

		// signed left shift is UB for negative numbers so use unsigned-signed casts
		CY1 += int(unsigned(DX12) << 4);
		CY2 += int(unsigned(DX23) << 4);
		CY3 += int(unsigned(DX31) << 4);
		ZY += DZy;
	}
}

} // namespace meshopt

meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	using namespace meshopt;

	assert(index_count % 3 == 0);
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	meshopt_Allocator allocator;

	size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

	meshopt_OverdrawStatistics result = {};

	float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
	float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};

	for (size_t i = 0; i < vertex_count; ++i)
	{
		const float* v = vertex_positions + i * vertex_stride_float;

		for (int j = 0; j < 3; ++j)
		{
			minv[j] = min(minv[j], v[j]);
			maxv[j] = max(maxv[j], v[j]);
		}
	}

	float extent = max(maxv[0] - minv[0], max(maxv[1] - minv[1], maxv[2] - minv[2]));
	float scale = kViewport / extent;

	float* triangles = allocator.allocate<float>(index_count * 3);

	for (size_t i = 0; i < index_count; ++i)
	{
		unsigned int index = indices[i];
		assert(index < vertex_count);

		const float* v = vertex_positions + index * vertex_stride_float;

		triangles[i * 3 + 0] = (v[0] - minv[0]) * scale;
		triangles[i * 3 + 1] = (v[1] - minv[1]) * scale;
		triangles[i * 3 + 2] = (v[2] - minv[2]) * scale;
	}

	OverdrawBuffer* buffer = allocator.allocate<OverdrawBuffer>(1);

	for (int axis = 0; axis < 3; ++axis)
	{
		memset(buffer, 0, sizeof(OverdrawBuffer));

		for (size_t i = 0; i < index_count; i += 3)
		{
			const float* vn0 = &triangles[3 * (i + 0)];
			const float* vn1 = &triangles[3 * (i + 1)];
			const float* vn2 = &triangles[3 * (i + 2)];

			switch (axis)
			{
			case 0:
				rasterize(buffer, vn0[2], vn0[1], vn0[0], vn1[2], vn1[1], vn1[0], vn2[2], vn2[1], vn2[0]);
				break;
			case 1:
				rasterize(buffer, vn0[0], vn0[2], vn0[1], vn1[0], vn1[2], vn1[1], vn2[0], vn2[2], vn2[1]);
				break;
			case 2:
				rasterize(buffer, vn0[1], vn0[0], vn0[2], vn1[1], vn1[0], vn1[2], vn2[1], vn2[0], vn2[2]);
				break;
			}
		}

		for (int y = 0; y < kViewport; ++y)
			for (int x = 0; x < kViewport; ++x)
				for (int s = 0; s < 2; ++s)
				{
					unsigned int overdraw = buffer->overdraw[y][x][s];

					result.pixels_covered += overdraw > 0;
					result.pixels_shaded += overdraw;
				}
	}

	result.overdraw = result.pixels_covered ? float(result.pixels_shaded) / float(result.pixels_covered) : 0.f;

	return result;
}
<|endoftext|>


<commit_before><commit_msg>Eliminate precarious use of const_cast<wchar*>(wstring.get()) Review URL: http://codereview.chromium.org/42617<commit_after><|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wifipropconnection.h"

#define CALIBRATE_DELAY 10

#define HTTP_PORT       80
#define TELNET_PORT     23
#define DISCOVER_PORT   2000

int resetPin = 12;
extern int verbose;

WiFiPropConnection::WiFiPropConnection()
    : m_ipaddr(NULL),
      m_socket(INVALID_SOCKET)
{
    m_loaderBaudRate = WIFI_LOADER_BAUD_RATE;
    m_fastLoaderBaudRate = WIFI_FAST_LOADER_BAUD_RATE;
    m_programBaudRate = WIFI_PROGRAM_BAUD_RATE;
}

WiFiPropConnection::~WiFiPropConnection()
{
    if (m_ipaddr)
        free(m_ipaddr);
    disconnect();
}

int WiFiPropConnection::setAddress(const char *ipaddr)
{
    if (m_ipaddr)
        free(m_ipaddr);

    if (!(m_ipaddr = (char *)malloc(strlen(ipaddr) + 1)))
        return -1;
    strcpy(m_ipaddr, ipaddr);

    if (GetInternetAddress(m_ipaddr, HTTP_PORT, &m_httpAddr) != 0)
        return -1;

    if (GetInternetAddress(m_ipaddr, TELNET_PORT, &m_telnetAddr) != 0)
        return -1;

    return 0;
}

int WiFiPropConnection::close()
{
    if (!isOpen())
        return -1;

    return 0;
}

int WiFiPropConnection::connect()
{
    if (!m_ipaddr)
        return -1;

    if (m_socket != INVALID_SOCKET)
        return -1;

    if (ConnectSocketTimeout(&m_telnetAddr, CONNECT_TIMEOUT, &m_socket) != 0)
        return -1;

    return 0;
}

int WiFiPropConnection::disconnect()
{
    if (m_socket == INVALID_SOCKET)
        return -1;

    CloseSocket(m_socket);
    m_socket = INVALID_SOCKET;

    return 0;
}

int WiFiPropConnection::identify(int *pVersion)
{
    return 0;
}

int WiFiPropConnection::loadImage(const uint8_t *image, int imageSize, LoadType loadType)
{
    uint8_t buffer[1024], *packet;
    int hdrCnt, result;

    /* use the initial loader baud rate */
    if (setBaudRate(loaderBaudRate()) != 0)
        return -1;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/load?reset-pin=%d&baud-rate=%d HTTP/1.1\r\n\
Content-Length: %d\r\n\
\r\n", resetPin, loaderBaudRate(), imageSize);

    if (!(packet = (uint8_t *)malloc(hdrCnt + imageSize)))
        return -1;

    memcpy(packet,  buffer, hdrCnt);
    memcpy(&packet[hdrCnt], image, imageSize);

    if (sendRequest(packet, hdrCnt + imageSize, buffer, sizeof(buffer), &result) == -1) {
        printf("error: load request failed\n");
        return -1;
    }
    else if (result != 200) {
        printf("error: load returned %d\n", result);
        return -1;
    }

    return 0;
}

#define MAX_IF_ADDRS    20
#define NAME_TAG        "\"name\": \""

int WiFiPropConnection::findModules(bool check, WiFiInfoList &list, int count)
{
    uint8_t txBuf[1024]; // BUG: get rid of this magic number!
    uint8_t rxBuf[1024]; // BUG: get rid of this magic number!
    IFADDR ifaddrs[MAX_IF_ADDRS];
    uint32_t *txNext;
    int ifCnt, tries, txCnt, cnt, i;
    SOCKADDR_IN addr;
    SOCKET sock;

    /* get all of the network interface addresses */
    if ((ifCnt = GetInterfaceAddresses(ifaddrs, MAX_IF_ADDRS)) < 0) {
        printf("error: GetInterfaceAddresses failed\n");
        return -1;
    }

    /* create a broadcast socket */
    if (OpenBroadcastSocket(DISCOVER_PORT, &sock) != 0) {
        printf("error: OpenBroadcastSocket failed\n");
        return -1;
    }

    /* initialize the broadcast message to indicate no modules found yet */
    txNext = (uint32_t *)txBuf;
    *txNext++ = 0; // indicates that this is a request not a response
    txCnt = sizeof(uint32_t);

    /* keep trying until we have this many attempts that return no new modules */
    tries = DISCOVER_ATTEMPTS;

    /* make a number of attempts at discovering modules */
    while (tries > 0) {
        int numberFound = 0;

        /* send the broadcast packet to all interfaces */
        for (i = 0; i < ifCnt; ++i) {
            SOCKADDR_IN bcastaddr;

            /* build a broadcast address */
            bcastaddr = ifaddrs[i].bcast;
            bcastaddr.sin_port = htons(DISCOVER_PORT);

            /* send the broadcast packet */
            if (SendSocketDataTo(sock, txBuf, txCnt, &bcastaddr) != txCnt) {
                perror("error: SendSocketDataTo failed");
                CloseSocket(sock);
                return -1;
            }
        }

        /* receive wifi module responses */
        while (SocketDataAvailableP(sock, DISCOVER_REPLY_TIMEOUT)) {

            /* get the next response */
            if ((cnt = ReceiveSocketDataAndAddress(sock, rxBuf, sizeof(rxBuf) - 1, &addr)) < 0) {
                printf("error: ReceiveSocketData failed\n");
                CloseSocket(sock);
                return -3;
            }
            rxBuf[cnt] = '\0';

            /* only process replies */
            if (cnt >= sizeof(uint32_t) && *(uint32_t *)rxBuf != 0) {
                std::string addressStr(AddressToString(&addr));
                const char *name, *p, *p2;
                char nameBuffer[128];
                printf("Address: %08x\n", addr.sin_addr.s_addr);

                /* make sure we don't already have a response from this module */
                WiFiInfoList::iterator i = list.begin();
                bool skip = false;
                while (i != list.end()) {
                    if (i->address() == addressStr) {
                    printf("Skipping duplicate\n");
                        skip = true;
                        break;
                    }
                    ++i;
                }
                if (skip)
                    continue;

                /* count this as a module found on this attempt */
                ++numberFound;

                /* add the module's ip address to the next broadcast message */
                if (txCnt < sizeof(txBuf)) {
                    *txNext++ = addr.sin_addr.s_addr;
                    txCnt += sizeof(uint32_t);
                }

                if (verbose)
                    printf("from %s got: %s", AddressToString(&addr), rxBuf);

                if (!(p = strstr((char *)rxBuf, NAME_TAG)))
                    name = "";
                else {
                    p += strlen(NAME_TAG);
                    if (!(p2 = strchr(p, '"'))) {
                        CloseSocket(sock);
                        return -1;
                    }
                    else if (p2 - p >= (int)sizeof(nameBuffer)) {
                        CloseSocket(sock);
                        return -1;
                    }
                    strncpy(nameBuffer, p, p2 - p);
                    nameBuffer[p2 - p] = '\0';
                    name = nameBuffer;
                }

                WiFiInfo info(name, addressStr);
                list.push_back(info);

                if (count > 0 && --count == 0) {
                    CloseSocket(sock);
                    return 0;
                }
            }
        }

        /* if we found at least one module, reset the retry counter */
        if (numberFound > 0)
            tries = DISCOVER_ATTEMPTS;

        /* otherwise, decrement the number of attempts remaining */
        else
            --tries;
    }

    /* close the socket */
    CloseSocket(sock);

    /* return successfully */
    return 0;
}

bool WiFiPropConnection::isOpen()
{
    return m_socket != INVALID_SOCKET;
}

int WiFiPropConnection::setName(const char *name)
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /system/update?name=%s HTTP/1.1\r\n\
\r\n", name);

    if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
        printf("error: name update request failed\n");
        return -1;
    }
    else if (result != 204) {
        printf("error: name update returned %d\n", result);
        return -1;
    }

    return 0;
}

int WiFiPropConnection::generateResetSignal()
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/reset?reset-pin=%d HTTP/1.1\r\n\
\r\n", resetPin);

    if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
        printf("error: reset request failed\n");
        return -1;
    }
    else if (result != 200) {
        printf("error: reset returned %d\n", result);
        return -1;
    }

    return 0;
}

int WiFiPropConnection::sendData(const uint8_t *buf, int len)
{
    if (!isOpen())
        return -1;
    return SendSocketData(m_socket, buf, len);
}

int WiFiPropConnection::receiveDataTimeout(uint8_t *buf, int len, int timeout)
{
    if (!isOpen())
        return -1;
    return ReceiveSocketDataTimeout(m_socket, buf, len, timeout);
}

int WiFiPropConnection::receiveDataExactTimeout(uint8_t *buf, int len, int timeout)
{
    if (!isOpen())
        return -1;
    return ReceiveSocketDataExactTimeout(m_socket, buf, len, timeout);
}

int WiFiPropConnection::setBaudRate(int baudRate)
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    if (baudRate != m_baudRate) {

        hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/set-baud-rate?baud-rate=%d HTTP/1.1\r\n\
\r\n", baudRate);

        if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
            printf("error: set-baud-rate request failed\n");
            return -1;
        }
        else if (result != 200) {
            printf("error: set-baud-rate returned %d\n", result);
            return -1;
        }

        m_baudRate = baudRate;
    }

    return 0;
}

int WiFiPropConnection::terminal(bool checkForExit, bool pstMode)
{
    if (!connect())
        return -1;
    SocketTerminal(m_socket, checkForExit, pstMode);
    disconnect();
    return 0;
}

int WiFiPropConnection::sendRequest(uint8_t *req, int reqSize, uint8_t *res, int resMax, int *pResult)
{
    SOCKET sock;
    char buf[80];
    int cnt;

    if (ConnectSocketTimeout(&m_httpAddr, CONNECT_TIMEOUT, &sock) != 0) {
        printf("error: connect failed\n");
        return -1;
    }

    if (verbose) {
        printf("REQ: %d\n", reqSize);
        dumpHdr(req, reqSize);
    }

    if (SendSocketData(sock, req, reqSize) != reqSize) {
        printf("error: send request failed\n");
        CloseSocket(sock);
        return -1;
    }

    cnt = ReceiveSocketDataTimeout(sock, res, resMax, 10000);
    CloseSocket(sock);

    if (cnt == -1) {
        printf("error: receive response failed\n");
        return -1;
    }

    if (verbose) {
        printf("RES: %d\n", cnt);
        dumpResponse(res, cnt);
    }

    if (sscanf((char *)res, "%s %d", buf, pResult) != 2)
        return -1;

    return cnt;
}

void WiFiPropConnection::dumpHdr(const uint8_t *buf, int size)
{
    int startOfLine = true;
    const uint8_t *p = buf;
    while (p < buf + size) {
        if (*p == '\r') {
            if (startOfLine)
                break;
            startOfLine = true;
            putchar('\n');
        }
        else if (*p != '\n') {
            startOfLine = false;
            putchar(*p);
        }
        ++p;
    }
    putchar('\n');
}

void WiFiPropConnection::dumpResponse(const uint8_t *buf, int size)
{
    int startOfLine = true;
    const uint8_t *p = buf;
    const uint8_t *save;
    int cnt;

    while (p < buf + size) {
        if (*p == '\r') {
            if (startOfLine) {
                ++p;
                if (*p == '\n')
                    ++p;
                break;
            }
            startOfLine = true;
            putchar('\n');
        }
        else if (*p != '\n') {
            startOfLine = false;
            putchar(*p);
        }
        ++p;
    }
    putchar('\n');

    save = p;
    while (p < buf + size) {
        if (*p == '\r')
            putchar('\n');
        else if (*p != '\n')
            putchar(*p);
        ++p;
    }

    p = save;
    cnt = 0;
    while (p < buf + size) {
        printf("%02x ", *p++);
        if ((++cnt % 16) == 0)
            putchar('\n');
    }
    if ((cnt % 16) != 0)
        putchar('\n');
}

<commit_msg>Suppress all of the discovery status messages when -v is not specied.<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wifipropconnection.h"

#define CALIBRATE_DELAY 10

#define HTTP_PORT       80
#define TELNET_PORT     23
#define DISCOVER_PORT   2000

int resetPin = 12;
extern int verbose;

WiFiPropConnection::WiFiPropConnection()
    : m_ipaddr(NULL),
      m_socket(INVALID_SOCKET)
{
    m_loaderBaudRate = WIFI_LOADER_BAUD_RATE;
    m_fastLoaderBaudRate = WIFI_FAST_LOADER_BAUD_RATE;
    m_programBaudRate = WIFI_PROGRAM_BAUD_RATE;
}

WiFiPropConnection::~WiFiPropConnection()
{
    if (m_ipaddr)
        free(m_ipaddr);
    disconnect();
}

int WiFiPropConnection::setAddress(const char *ipaddr)
{
    if (m_ipaddr)
        free(m_ipaddr);

    if (!(m_ipaddr = (char *)malloc(strlen(ipaddr) + 1)))
        return -1;
    strcpy(m_ipaddr, ipaddr);

    if (GetInternetAddress(m_ipaddr, HTTP_PORT, &m_httpAddr) != 0)
        return -1;

    if (GetInternetAddress(m_ipaddr, TELNET_PORT, &m_telnetAddr) != 0)
        return -1;

    return 0;
}

int WiFiPropConnection::close()
{
    if (!isOpen())
        return -1;

    return 0;
}

int WiFiPropConnection::connect()
{
    if (!m_ipaddr)
        return -1;

    if (m_socket != INVALID_SOCKET)
        return -1;

    if (ConnectSocketTimeout(&m_telnetAddr, CONNECT_TIMEOUT, &m_socket) != 0)
        return -1;

    return 0;
}

int WiFiPropConnection::disconnect()
{
    if (m_socket == INVALID_SOCKET)
        return -1;

    CloseSocket(m_socket);
    m_socket = INVALID_SOCKET;

    return 0;
}

int WiFiPropConnection::identify(int *pVersion)
{
    return 0;
}

int WiFiPropConnection::loadImage(const uint8_t *image, int imageSize, LoadType loadType)
{
    uint8_t buffer[1024], *packet;
    int hdrCnt, result;

    /* use the initial loader baud rate */
    if (setBaudRate(loaderBaudRate()) != 0)
        return -1;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/load?reset-pin=%d&baud-rate=%d HTTP/1.1\r\n\
Content-Length: %d\r\n\
\r\n", resetPin, loaderBaudRate(), imageSize);

    if (!(packet = (uint8_t *)malloc(hdrCnt + imageSize)))
        return -1;

    memcpy(packet,  buffer, hdrCnt);
    memcpy(&packet[hdrCnt], image, imageSize);

    if (sendRequest(packet, hdrCnt + imageSize, buffer, sizeof(buffer), &result) == -1) {
        printf("error: load request failed\n");
        return -1;
    }
    else if (result != 200) {
        printf("error: load returned %d\n", result);
        return -1;
    }

    return 0;
}

#define MAX_IF_ADDRS    20
#define NAME_TAG        "\"name\": \""

int WiFiPropConnection::findModules(bool check, WiFiInfoList &list, int count)
{
    uint8_t txBuf[1024]; // BUG: get rid of this magic number!
    uint8_t rxBuf[1024]; // BUG: get rid of this magic number!
    IFADDR ifaddrs[MAX_IF_ADDRS];
    uint32_t *txNext;
    int ifCnt, tries, txCnt, cnt, i;
    SOCKADDR_IN addr;
    SOCKET sock;

    /* get all of the network interface addresses */
    if ((ifCnt = GetInterfaceAddresses(ifaddrs, MAX_IF_ADDRS)) < 0) {
        printf("error: GetInterfaceAddresses failed\n");
        return -1;
    }

    /* create a broadcast socket */
    if (OpenBroadcastSocket(DISCOVER_PORT, &sock) != 0) {
        printf("error: OpenBroadcastSocket failed\n");
        return -1;
    }

    /* initialize the broadcast message to indicate no modules found yet */
    txNext = (uint32_t *)txBuf;
    *txNext++ = 0; // indicates that this is a request not a response
    txCnt = sizeof(uint32_t);

    /* keep trying until we have this many attempts that return no new modules */
    tries = DISCOVER_ATTEMPTS;

    /* make a number of attempts at discovering modules */
    while (tries > 0) {
        int numberFound = 0;

        /* send the broadcast packet to all interfaces */
        for (i = 0; i < ifCnt; ++i) {
            SOCKADDR_IN bcastaddr;

            /* build a broadcast address */
            bcastaddr = ifaddrs[i].bcast;
            bcastaddr.sin_port = htons(DISCOVER_PORT);

            /* send the broadcast packet */
            if (SendSocketDataTo(sock, txBuf, txCnt, &bcastaddr) != txCnt) {
                perror("error: SendSocketDataTo failed");
                CloseSocket(sock);
                return -1;
            }
        }

        /* receive wifi module responses */
        while (SocketDataAvailableP(sock, DISCOVER_REPLY_TIMEOUT)) {

            /* get the next response */
            if ((cnt = ReceiveSocketDataAndAddress(sock, rxBuf, sizeof(rxBuf) - 1, &addr)) < 0) {
                printf("error: ReceiveSocketData failed\n");
                CloseSocket(sock);
                return -3;
            }
            rxBuf[cnt] = '\0';

            /* only process replies */
            if (cnt >= sizeof(uint32_t) && *(uint32_t *)rxBuf != 0) {
                std::string addressStr(AddressToString(&addr));
                const char *name, *p, *p2;
                char nameBuffer[128];

                /* make sure we don't already have a response from this module */
                WiFiInfoList::iterator i = list.begin();
                bool skip = false;
                while (i != list.end()) {
                    if (i->address() == addressStr) {
                        if (verbose)
                            printf("Skipping duplicate: %s\n", AddressToString(&addr));
                        skip = true;
                        break;
                    }
                    ++i;
                }
                if (skip)
                    continue;

                /* count this as a module found on this attempt */
                ++numberFound;

                /* add the module's ip address to the next broadcast message */
                if (txCnt < sizeof(txBuf)) {
                    *txNext++ = addr.sin_addr.s_addr;
                    txCnt += sizeof(uint32_t);
                }

                if (verbose)
                    printf("from %s got: %s", AddressToString(&addr), rxBuf);

                if (!(p = strstr((char *)rxBuf, NAME_TAG)))
                    name = "";
                else {
                    p += strlen(NAME_TAG);
                    if (!(p2 = strchr(p, '"'))) {
                        CloseSocket(sock);
                        return -1;
                    }
                    else if (p2 - p >= (int)sizeof(nameBuffer)) {
                        CloseSocket(sock);
                        return -1;
                    }
                    strncpy(nameBuffer, p, p2 - p);
                    nameBuffer[p2 - p] = '\0';
                    name = nameBuffer;
                }

                WiFiInfo info(name, addressStr);
                list.push_back(info);

                if (count > 0 && --count == 0) {
                    CloseSocket(sock);
                    return 0;
                }
            }
        }

        /* if we found at least one module, reset the retry counter */
        if (numberFound > 0)
            tries = DISCOVER_ATTEMPTS;

        /* otherwise, decrement the number of attempts remaining */
        else
            --tries;
    }

    /* close the socket */
    CloseSocket(sock);

    /* return successfully */
    return 0;
}

bool WiFiPropConnection::isOpen()
{
    return m_socket != INVALID_SOCKET;
}

int WiFiPropConnection::setName(const char *name)
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /system/update?name=%s HTTP/1.1\r\n\
\r\n", name);

    if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
        printf("error: name update request failed\n");
        return -1;
    }
    else if (result != 204) {
        printf("error: name update returned %d\n", result);
        return -1;
    }

    return 0;
}

int WiFiPropConnection::generateResetSignal()
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/reset?reset-pin=%d HTTP/1.1\r\n\
\r\n", resetPin);

    if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
        printf("error: reset request failed\n");
        return -1;
    }
    else if (result != 200) {
        printf("error: reset returned %d\n", result);
        return -1;
    }

    return 0;
}

int WiFiPropConnection::sendData(const uint8_t *buf, int len)
{
    if (!isOpen())
        return -1;
    return SendSocketData(m_socket, buf, len);
}

int WiFiPropConnection::receiveDataTimeout(uint8_t *buf, int len, int timeout)
{
    if (!isOpen())
        return -1;
    return ReceiveSocketDataTimeout(m_socket, buf, len, timeout);
}

int WiFiPropConnection::receiveDataExactTimeout(uint8_t *buf, int len, int timeout)
{
    if (!isOpen())
        return -1;
    return ReceiveSocketDataExactTimeout(m_socket, buf, len, timeout);
}

int WiFiPropConnection::setBaudRate(int baudRate)
{
    uint8_t buffer[1024];
    int hdrCnt, result;

    if (baudRate != m_baudRate) {

        hdrCnt = snprintf((char *)buffer, sizeof(buffer), "\
POST /propeller/set-baud-rate?baud-rate=%d HTTP/1.1\r\n\
\r\n", baudRate);

        if (sendRequest(buffer, hdrCnt, buffer, sizeof(buffer), &result) == -1) {
            printf("error: set-baud-rate request failed\n");
            return -1;
        }
        else if (result != 200) {
            printf("error: set-baud-rate returned %d\n", result);
            return -1;
        }

        m_baudRate = baudRate;
    }

    return 0;
}

int WiFiPropConnection::terminal(bool checkForExit, bool pstMode)
{
    if (!connect())
        return -1;
    SocketTerminal(m_socket, checkForExit, pstMode);
    disconnect();
    return 0;
}

int WiFiPropConnection::sendRequest(uint8_t *req, int reqSize, uint8_t *res, int resMax, int *pResult)
{
    SOCKET sock;
    char buf[80];
    int cnt;

    if (ConnectSocketTimeout(&m_httpAddr, CONNECT_TIMEOUT, &sock) != 0) {
        printf("error: connect failed\n");
        return -1;
    }

    if (verbose) {
        printf("REQ: %d\n", reqSize);
        dumpHdr(req, reqSize);
    }

    if (SendSocketData(sock, req, reqSize) != reqSize) {
        printf("error: send request failed\n");
        CloseSocket(sock);
        return -1;
    }

    cnt = ReceiveSocketDataTimeout(sock, res, resMax, 10000);
    CloseSocket(sock);

    if (cnt == -1) {
        printf("error: receive response failed\n");
        return -1;
    }

    if (verbose) {
        printf("RES: %d\n", cnt);
        dumpResponse(res, cnt);
    }

    if (sscanf((char *)res, "%s %d", buf, pResult) != 2)
        return -1;

    return cnt;
}

void WiFiPropConnection::dumpHdr(const uint8_t *buf, int size)
{
    int startOfLine = true;
    const uint8_t *p = buf;
    while (p < buf + size) {
        if (*p == '\r') {
            if (startOfLine)
                break;
            startOfLine = true;
            putchar('\n');
        }
        else if (*p != '\n') {
            startOfLine = false;
            putchar(*p);
        }
        ++p;
    }
    putchar('\n');
}

void WiFiPropConnection::dumpResponse(const uint8_t *buf, int size)
{
    int startOfLine = true;
    const uint8_t *p = buf;
    const uint8_t *save;
    int cnt;

    while (p < buf + size) {
        if (*p == '\r') {
            if (startOfLine) {
                ++p;
                if (*p == '\n')
                    ++p;
                break;
            }
            startOfLine = true;
            putchar('\n');
        }
        else if (*p != '\n') {
            startOfLine = false;
            putchar(*p);
        }
        ++p;
    }
    putchar('\n');

    save = p;
    while (p < buf + size) {
        if (*p == '\r')
            putchar('\n');
        else if (*p != '\n')
            putchar(*p);
        ++p;
    }

    p = save;
    cnt = 0;
    while (p < buf + size) {
        printf("%02x ", *p++);
        if ((++cnt % 16) == 0)
            putchar('\n');
    }
    if ((cnt % 16) != 0)
        putchar('\n');
}

<|endoftext|>