<commit_before>//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting a description of a target
// register file for a code generator.  It uses instances of the Register,
// RegisterAliases, and RegisterClass classes to gather this information.
//
//===----------------------------------------------------------------------===//

#include "RegisterInfoEmitter.h"
#include "CodeGenTarget.h"
#include "CodeGenRegisters.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
#include <set>
using namespace llvm;

// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(std::ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Target Register Enum Values", OS);
  OS << "namespace llvm {\n\n";

  if (!Namespace.empty())
    OS << "namespace " << Namespace << " {\n";
  OS << "  enum {\n    NoRegister,\n";

  for (unsigned i = 0, e = Registers.size(); i != e; ++i)
    OS << "    " << Registers[i].getName() << ", \t// " << i+1 << "\n";

  OS << "  };\n";
  if (!Namespace.empty())
    OS << "}\n";
  OS << "} // End llvm namespace \n";
}

void RegisterInfoEmitter::runHeader(std::ostream &OS) {
  EmitSourceFileHeader("Register Information Header Fragment", OS);
  CodeGenTarget Target;
  const std::string &TargetName = Target.getName();
  std::string ClassName = TargetName + "GenRegisterInfo";

  OS << "#include \"llvm/Target/MRegisterInfo.h\"\n\n";

  OS << "namespace llvm {\n\n";

  OS << "struct " << ClassName << " : public MRegisterInfo {\n"
     << "  " << ClassName
     << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n"
     << "  const unsigned* getCalleeSaveRegs() const;\n"
     << "};\n\n";

  std::vector<Record*> RegisterClasses =
    Records.getAllDerivedDefinitions("RegisterClass");

  OS << "namespace " << TargetName << " { // Register classes\n";
  for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
    const std::string &Name = RegisterClasses[i]->getName();
    if (Name.size() < 9 || Name[9] != '.')       // Ignore anonymous classes
      OS << "  extern TargetRegisterClass *" << Name << "RegisterClass;\n";
  }
  OS << "} // end of namespace " << TargetName << "\n\n";
  OS << "} // End llvm namespace \n";
}

// RegisterInfoEmitter::run - Main register file description emitter.
//
void RegisterInfoEmitter::run(std::ostream &OS) {
  CodeGenTarget Target;
  EmitSourceFileHeader("Register Information Source Fragment", OS);

  OS << "namespace llvm {\n\n";

  // Start out by emitting each of the register classes... to do this, we build
  // a set of registers which belong to a register class, this is to ensure that
  // each register is only in a single register class.
  //
  const std::vector<CodeGenRegisterClass> &RegisterClasses =
    Target.getRegisterClasses();

  std::set<Record*> RegistersFound;
  std::vector<std::string> RegClassNames;

  // Loop over all of the register classes... emitting each one.
  OS << "namespace {     // Register classes...\n";

  // RegClassesBelongedTo - Keep track of which register classes each reg
  // belongs to.
  std::multimap<Record*, const CodeGenRegisterClass*> RegClassesBelongedTo;

  for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
    const CodeGenRegisterClass &RC = RegisterClasses[rc];

    std::string Name = RC.getName();
    if (Name.size() > 9 && Name[9] == '.') {
      static unsigned AnonCounter = 0;
      Name = "AnonRegClass_"+utostr(AnonCounter++);
    }

    RegClassNames.push_back(Name);

    // Emit the register list now...
    OS << "  // " << Name << " Register Class...\n  const unsigned " << Name
       << "[] = {\n    ";
    for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) {
      Record *Reg = RC.Elements[i];
      if (RegistersFound.count(Reg))
        throw "Register '" + Reg->getName() +
              "' included in multiple register classes!";
      RegistersFound.insert(Reg);
      OS << getQualifiedName(Reg) << ", ";

      // Keep track of which regclasses this register is in.
      RegClassesBelongedTo.insert(std::make_pair(Reg, &RC));
    }
    OS << "\n  };\n\n";

    OS << "  struct " << Name << "Class : public TargetRegisterClass {\n"
       << "    " << Name << "Class() : TargetRegisterClass("
       << RC.SpillSize/8 << ", " << RC.SpillAlignment/8 << ", " << Name << ", "
       << Name << " + " << RC.Elements.size() << ") {}\n"
       << RC.MethodDefinitions << "  } " << Name << "Instance;\n\n";
  }

  OS << "  const TargetRegisterClass* const RegisterClasses[] = {\n";
  for (unsigned i = 0, e = RegClassNames.size(); i != e; ++i)
    OS << "    &" << RegClassNames[i] << "Instance,\n";
  OS << "  };\n";

  // Emit register class aliases...
  std::map<Record*, std::set<Record*> > RegisterAliases;
  const std::vector<CodeGenRegister> &Regs = Target.getRegisters();

  for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
    Record *R = Regs[i].TheDef;
    ListInit *LI = Regs[i].TheDef->getValueAsListInit("Aliases");
    // Add information that R aliases all of the elements in the list... and
    // that everything in the list aliases R.
    for (unsigned j = 0, e = LI->getSize(); j != e; ++j) {
      DefInit *Reg = dynamic_cast<DefInit*>(LI->getElement(j));
      if (!Reg) throw "ERROR: Alias list element is not a def!";
      if (RegisterAliases[R].count(Reg->getDef()))
        std::cerr << "Warning: register alias between " << getQualifiedName(R)
                  << " and " << getQualifiedName(Reg->getDef())
                  << " specified multiple times!\n";
      RegisterAliases[R].insert(Reg->getDef());

      if (RegisterAliases[Reg->getDef()].count(R))
        std::cerr << "Warning: register alias between " << getQualifiedName(R)
                  << " and " << getQualifiedName(Reg->getDef())
                  << " specified multiple times!\n";
      RegisterAliases[Reg->getDef()].insert(R);
    }
  }

  if (!RegisterAliases.empty())
    OS << "\n\n  // Register Alias Sets...\n";

  // Emit the empty alias list
  OS << "  const unsigned Empty_AliasSet[] = { 0 };\n";
  // Loop over all of the registers which have aliases, emitting the alias list
  // to memory.
  for (std::map<Record*, std::set<Record*> >::iterator
         I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) {
    OS << "  const unsigned " << I->first->getName() << "_AliasSet[] = { ";
    for (std::set<Record*>::iterator ASI = I->second.begin(),
           E = I->second.end(); ASI != E; ++ASI)
      OS << getQualifiedName(*ASI) << ", ";
    OS << "0 };\n";
  }

  OS << "\n  const MRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
  OS << "    { \"NOREG\",\t0,\t\t0,\t0 },\n";

  // Now that register alias sets have been emitted, emit the register
  // descriptors now.
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    OS << "    { \"";
    if (!Reg.TheDef->getValueAsString("Name").empty())
      OS << Reg.TheDef->getValueAsString("Name");
    else
      OS << Reg.getName();
    OS << "\",\t";
    if (RegisterAliases.count(Reg.TheDef))
      OS << Reg.getName() << "_AliasSet,\t";
    else
      OS << "Empty_AliasSet,\t";

    // Figure out what the size and alignment of the spill slots are for this
    // reg.  This may be explicitly declared in the register, or it may be
    // inferred from the register classes it is part of.
    std::multimap<Record*, const CodeGenRegisterClass*>::iterator I, E;
    tie(I, E) = RegClassesBelongedTo.equal_range(Reg.TheDef);
    unsigned SpillSize = Reg.DeclaredSpillSize;
    unsigned SpillAlign = Reg.DeclaredSpillAlignment;
    for (; I != E; ++I) {   // For each reg class this belongs to.
      const CodeGenRegisterClass *RC = I->second;
      if (SpillSize == 0)
        SpillSize = RC->SpillSize;
      else if (SpillSize != RC->SpillSize)
        throw "Spill size for regclass '" + RC->getName() +
              "' doesn't match spill sized already inferred for register '" +
              Reg.getName() + "'!";
      if (SpillAlign == 0)
        SpillAlign = RC->SpillAlignment;
      else if (SpillAlign != RC->SpillAlignment)
        throw "Spill alignment for regclass '" + RC->getName() +
              "' doesn't match spill sized already inferred for register '" +
              Reg.getName() + "'!";
    }

    OS << SpillSize << ", " << SpillAlign << " },\n";
  }
  OS << "  };\n";      // End of register descriptors...
  OS << "}\n\n";       // End of anonymous namespace...

  OS << "namespace " << Target.getName() << " { // Register classes\n";
  for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
    const std::string &Name = RegisterClasses[i].getName();
    if (Name.size() < 9 || Name[9] != '.')    // Ignore anonymous classes
      OS << "  TargetRegisterClass *" << Name << "RegisterClass = &"
         << Name << "Instance;\n";
  }
  OS << "} // end of namespace " << Target.getName() << "\n\n";

  std::string ClassName = Target.getName() + "GenRegisterInfo";

  // Emit the constructor of the class...
  OS << ClassName << "::" << ClassName
     << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n"
     << "  : MRegisterInfo(RegisterDescriptors, " << Registers.size()+1
     << ", RegisterClasses, RegisterClasses+" << RegClassNames.size() << ",\n "
     << "                 CallFrameSetupOpcode, CallFrameDestroyOpcode) {}\n\n";

  // Emit the getCalleeSaveRegs method...
  OS << "const unsigned* " << ClassName << "::getCalleeSaveRegs() const {\n"
     << "  static const unsigned CalleeSaveRegs[] = {\n    ";

  const std::vector<Record*> &CSR = Target.getCalleeSavedRegisters();
  for (unsigned i = 0, e = CSR.size(); i != e; ++i)
    OS << getQualifiedName(CSR[i]) << ", ";
  OS << " 0\n  };\n  return CalleeSaveRegs;\n}\n\n";
  OS << "} // End llvm namespace \n";
}
<commit_msg>Refactor to use Target.getRegisterClasses consistently, which provides anonymous regclass definition renaming.<commit_after>//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting a description of a target
// register file for a code generator.  It uses instances of the Register,
// RegisterAliases, and RegisterClass classes to gather this information.
//
//===----------------------------------------------------------------------===//

#include "RegisterInfoEmitter.h"
#include "CodeGenTarget.h"
#include "CodeGenRegisters.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
#include <set>
using namespace llvm;

// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(std::ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Target Register Enum Values", OS);
  OS << "namespace llvm {\n\n";

  if (!Namespace.empty())
    OS << "namespace " << Namespace << " {\n";
  OS << "  enum {\n    NoRegister,\n";

  for (unsigned i = 0, e = Registers.size(); i != e; ++i)
    OS << "    " << Registers[i].getName() << ", \t// " << i+1 << "\n";

  OS << "  };\n";
  if (!Namespace.empty())
    OS << "}\n";
  OS << "} // End llvm namespace \n";
}

void RegisterInfoEmitter::runHeader(std::ostream &OS) {
  EmitSourceFileHeader("Register Information Header Fragment", OS);
  CodeGenTarget Target;
  const std::string &TargetName = Target.getName();
  std::string ClassName = TargetName + "GenRegisterInfo";

  OS << "#include \"llvm/Target/MRegisterInfo.h\"\n\n";

  OS << "namespace llvm {\n\n";

  OS << "struct " << ClassName << " : public MRegisterInfo {\n"
     << "  " << ClassName
     << "(int CallFrameSetupOpcode = -1, int CallFrameDestroyOpcode = -1);\n"
     << "  const unsigned* getCalleeSaveRegs() const;\n"
     << "};\n\n";

  const std::vector<CodeGenRegisterClass> &RegisterClasses =
    Target.getRegisterClasses();

  if (!RegisterClasses.empty()) {
    OS << "namespace " << RegisterClasses[0].Namespace
       << " { // Register classes\n";
    for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
      const std::string &Name = RegisterClasses[i].getName();
      OS << "  extern TargetRegisterClass * const "<< Name <<"RegisterClass;\n";
    }
    OS << "} // end of namespace " << TargetName << "\n\n";
  }
  OS << "} // End llvm namespace \n";
}

// RegisterInfoEmitter::run - Main register file description emitter.
//
void RegisterInfoEmitter::run(std::ostream &OS) {
  CodeGenTarget Target;
  EmitSourceFileHeader("Register Information Source Fragment", OS);

  OS << "namespace llvm {\n\n";

  // Start out by emitting each of the register classes... to do this, we build
  // a set of registers which belong to a register class, this is to ensure that
  // each register is only in a single register class.
  //
  const std::vector<CodeGenRegisterClass> &RegisterClasses =
    Target.getRegisterClasses();

  std::set<Record*> RegistersFound;

  // Loop over all of the register classes... emitting each one.
  OS << "namespace {     // Register classes...\n";

  // RegClassesBelongedTo - Keep track of which register classes each reg
  // belongs to.
  std::multimap<Record*, const CodeGenRegisterClass*> RegClassesBelongedTo;

  for (unsigned rc = 0, e = RegisterClasses.size(); rc != e; ++rc) {
    const CodeGenRegisterClass &RC = RegisterClasses[rc];

    // Give the register class a legal C name if it's anonymous.
    std::string Name = RC.TheDef->getName();

    // Emit the register list now.
    OS << "  // " << Name << " Register Class...\n  const unsigned " << Name
       << "[] = {\n    ";
    for (unsigned i = 0, e = RC.Elements.size(); i != e; ++i) {
      Record *Reg = RC.Elements[i];
      if (RegistersFound.count(Reg))
        throw "Register '" + Reg->getName() +
              "' included in multiple register classes!";
      RegistersFound.insert(Reg);
      OS << getQualifiedName(Reg) << ", ";

      // Keep track of which regclasses this register is in.
      RegClassesBelongedTo.insert(std::make_pair(Reg, &RC));
    }
    OS << "\n  };\n\n";

    OS << "  struct " << Name << "Class : public TargetRegisterClass {\n"
       << "    " << Name << "Class() : TargetRegisterClass("
       << RC.SpillSize/8 << ", " << RC.SpillAlignment/8 << ", " << Name << ", "
       << Name << " + " << RC.Elements.size() << ") {}\n"
       << RC.MethodDefinitions << "  };\n\n";
  }
  OS << "}  // end anonymous namespace\n\n";

  // Now that all of the structs have been emitted, emit the instances.
  if (!RegisterClasses.empty()) {
    OS << "namespace " << RegisterClasses[0].Namespace
       << " {   // Register class instances\n";
    for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i)
      OS << "  " << RegisterClasses[i].getName()  << "Class\t"
         << RegisterClasses[i].getName() << "RegClassInstance;\n";
    OS << "}\n";
  }

  OS << "\nnamespace {\n";
  OS << "  const TargetRegisterClass* const RegisterClasses[] = {\n";
  for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i)
    OS << "    &" << getQualifiedName(RegisterClasses[i].TheDef)
       << "RegClassInstance,\n";
  OS << "  };\n";

  // Emit register class aliases...
  std::map<Record*, std::set<Record*> > RegisterAliases;
  const std::vector<CodeGenRegister> &Regs = Target.getRegisters();

  for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
    Record *R = Regs[i].TheDef;
    ListInit *LI = Regs[i].TheDef->getValueAsListInit("Aliases");
    // Add information that R aliases all of the elements in the list... and
    // that everything in the list aliases R.
    for (unsigned j = 0, e = LI->getSize(); j != e; ++j) {
      DefInit *Reg = dynamic_cast<DefInit*>(LI->getElement(j));
      if (!Reg) throw "ERROR: Alias list element is not a def!";
      if (RegisterAliases[R].count(Reg->getDef()))
        std::cerr << "Warning: register alias between " << getQualifiedName(R)
                  << " and " << getQualifiedName(Reg->getDef())
                  << " specified multiple times!\n";
      RegisterAliases[R].insert(Reg->getDef());

      if (RegisterAliases[Reg->getDef()].count(R))
        std::cerr << "Warning: register alias between " << getQualifiedName(R)
                  << " and " << getQualifiedName(Reg->getDef())
                  << " specified multiple times!\n";
      RegisterAliases[Reg->getDef()].insert(R);
    }
  }

  if (!RegisterAliases.empty())
    OS << "\n\n  // Register Alias Sets...\n";

  // Emit the empty alias list
  OS << "  const unsigned Empty_AliasSet[] = { 0 };\n";
  // Loop over all of the registers which have aliases, emitting the alias list
  // to memory.
  for (std::map<Record*, std::set<Record*> >::iterator
         I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) {
    OS << "  const unsigned " << I->first->getName() << "_AliasSet[] = { ";
    for (std::set<Record*>::iterator ASI = I->second.begin(),
           E = I->second.end(); ASI != E; ++ASI)
      OS << getQualifiedName(*ASI) << ", ";
    OS << "0 };\n";
  }

  OS << "\n  const MRegisterDesc RegisterDescriptors[] = { // Descriptors\n";
  OS << "    { \"NOREG\",\t0,\t\t0,\t0 },\n";

  // Now that register alias sets have been emitted, emit the register
  // descriptors now.
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    OS << "    { \"";
    if (!Reg.TheDef->getValueAsString("Name").empty())
      OS << Reg.TheDef->getValueAsString("Name");
    else
      OS << Reg.getName();
    OS << "\",\t";
    if (RegisterAliases.count(Reg.TheDef))
      OS << Reg.getName() << "_AliasSet,\t";
    else
      OS << "Empty_AliasSet,\t";

    // Figure out what the size and alignment of the spill slots are for this
    // reg.  This may be explicitly declared in the register, or it may be
    // inferred from the register classes it is part of.
    std::multimap<Record*, const CodeGenRegisterClass*>::iterator I, E;
    tie(I, E) = RegClassesBelongedTo.equal_range(Reg.TheDef);
    unsigned SpillSize = Reg.DeclaredSpillSize;
    unsigned SpillAlign = Reg.DeclaredSpillAlignment;
    for (; I != E; ++I) {   // For each reg class this belongs to.
      const CodeGenRegisterClass *RC = I->second;
      if (SpillSize == 0)
        SpillSize = RC->SpillSize;
      else if (SpillSize != RC->SpillSize)
        throw "Spill size for regclass '" + RC->getName() +
              "' doesn't match spill sized already inferred for register '" +
              Reg.getName() + "'!";
      if (SpillAlign == 0)
        SpillAlign = RC->SpillAlignment;
      else if (SpillAlign != RC->SpillAlignment)
        throw "Spill alignment for regclass '" + RC->getName() +
              "' doesn't match spill sized already inferred for register '" +
              Reg.getName() + "'!";
    }

    OS << SpillSize << ", " << SpillAlign << " },\n";
  }
  OS << "  };\n";      // End of register descriptors...
  OS << "}\n\n";       // End of anonymous namespace...

  if (!RegisterClasses.empty()) {
    OS << "namespace " << RegisterClasses[0].Namespace
       << " { // Register classes\n";
    for (unsigned i = 0, e = RegisterClasses.size(); i != e; ++i) {
      OS << "  TargetRegisterClass * const " << RegisterClasses[i].getName()
         << "RegisterClass = &" << getQualifiedName(RegisterClasses[i].TheDef)
         << "RegClassInstance;\n";
    }
    OS << "} // end of namespace " << RegisterClasses[0].Namespace << "\n\n";
  }

  std::string ClassName = Target.getName() + "GenRegisterInfo";

  // Emit the constructor of the class...
  OS << ClassName << "::" << ClassName
     << "(int CallFrameSetupOpcode, int CallFrameDestroyOpcode)\n"
     << "  : MRegisterInfo(RegisterDescriptors, " << Registers.size()+1
     << ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() <<",\n "
     << "                 CallFrameSetupOpcode, CallFrameDestroyOpcode) {}\n\n";

  // Emit the getCalleeSaveRegs method...
  OS << "const unsigned* " << ClassName << "::getCalleeSaveRegs() const {\n"
     << "  static const unsigned CalleeSaveRegs[] = {\n    ";

  const std::vector<Record*> &CSR = Target.getCalleeSavedRegisters();
  for (unsigned i = 0, e = CSR.size(); i != e; ++i)
    OS << getQualifiedName(CSR[i]) << ", ";
  OS << " 0\n  };\n  return CalleeSaveRegs;\n}\n\n";
  OS << "} // End llvm namespace \n";
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <pcl/common/time_trigger.h>
#include <pcl/common/time.h>
#include <iostream>

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::TimeTrigger (double interval, const callback_type& callback)
: callbacks_ ()
, interval_ (interval)
, quit_ (false)
, running_ (false)
, timer_thread_ ()
, condition_ ()
, condition_mutex_ ()
{
  timer_thread_ = boost::thread (boost::bind (&TimeTrigger::thread_function, this));
  registerCallback (callback);
}

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::TimeTrigger (double interval)
: callbacks_ ()
, interval_ (interval)
, quit_ (false)
, running_ (false)
, timer_thread_ ()
, condition_ ()
, condition_mutex_ ()
{
  timer_thread_ = boost::thread (boost::bind (&TimeTrigger::thread_function, this));
}

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::~TimeTrigger ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  quit_ = true;
  lock.unlock ();
  condition_.notify_all ();

  timer_thread_.join ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
boost::signals2::connection
pcl::TimeTrigger::registerCallback (const callback_type& callback)
{
  return (callbacks_.connect (callback));
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::setInterval (double interval_seconds)
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  interval_ = interval_seconds;
  // notify, since we could switch from a large interval to a shorter one -> interrupt waiting for timeout!
  condition_.notify_all ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::start ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  if (!running_)
  {
    running_ = true;
    condition_.notify_all ();
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::stop ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  if (running_)
  {
    running_ = false;
    condition_.notify_all ();
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::thread_function ()
{
  double time = 0;
  while (true)
  {
    time = getTime ();
    boost::unique_lock<boost::mutex> lock (condition_mutex_);
    if(quit_)
      break;
    if (!running_)
      condition_.wait (lock); // wait util start is called or destructor is called
    else
    {
      callbacks_();
      double rest = interval_ + time - getTime ();
#if defined(BOOST_HAS_WINTHREADS) && (BOOST_VERSION < 105500)
      //infinite timed_wait bug: https://svn.boost.org/trac/boost/ticket/9079
      if (rest > 0.0) // without a deadlock is possible, until notify() is called
        condition_.timed_wait (lock, boost::posix_time::microseconds (static_cast<int64_t> ((rest * 1000000))));
#else
      condition_.timed_wait (lock, boost::posix_time::microseconds (static_cast<int64_t> ((rest * 1000000))));
#endif
    }
  }
}

<commit_msg>Revert "remove pessimization"<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <pcl/common/time_trigger.h>
#include <pcl/common/time.h>
#include <iostream>

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::TimeTrigger (double interval, const callback_type& callback)
: callbacks_ ()
, interval_ (interval)
, quit_ (false)
, running_ (false)
, timer_thread_ ()
, condition_ ()
, condition_mutex_ ()
{
  timer_thread_ = boost::thread (boost::bind (&TimeTrigger::thread_function, this));
  registerCallback (callback);
}

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::TimeTrigger (double interval)
: callbacks_ ()
, interval_ (interval)
, quit_ (false)
, running_ (false)
, timer_thread_ ()
, condition_ ()
, condition_mutex_ ()
{
  timer_thread_ = boost::thread (boost::bind (&TimeTrigger::thread_function, this));
}

//////////////////////////////////////////////////////////////////////////////////////////////
pcl::TimeTrigger::~TimeTrigger ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  quit_ = true;
  condition_.notify_all ();
  lock.unlock ();

  timer_thread_.join ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
boost::signals2::connection
pcl::TimeTrigger::registerCallback (const callback_type& callback)
{
  return (callbacks_.connect (callback));
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::setInterval (double interval_seconds)
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  interval_ = interval_seconds;
  // notify, since we could switch from a large interval to a shorter one -> interrupt waiting for timeout!
  condition_.notify_all ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::start ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  if (!running_)
  {
    running_ = true;
    condition_.notify_all ();
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::stop ()
{
  boost::unique_lock<boost::mutex> lock (condition_mutex_);
  if (running_)
  {
    running_ = false;
    condition_.notify_all ();
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::TimeTrigger::thread_function ()
{
  double time = 0;
  while (true)
  {
    time = getTime ();
    boost::unique_lock<boost::mutex> lock (condition_mutex_);
    if(quit_)
      break;
    if (!running_)
      condition_.wait (lock); // wait util start is called or destructor is called
    else
    {
      callbacks_();
      double rest = interval_ + time - getTime ();
#if defined(BOOST_HAS_WINTHREADS) && (BOOST_VERSION < 105500)
      //infinite timed_wait bug: https://svn.boost.org/trac/boost/ticket/9079
      if (rest > 0.0) // without a deadlock is possible, until notify() is called
        condition_.timed_wait (lock, boost::posix_time::microseconds (static_cast<int64_t> ((rest * 1000000))));
#else
      condition_.timed_wait (lock, boost::posix_time::microseconds (static_cast<int64_t> ((rest * 1000000))));
#endif
    }
  }
}

<|endoftext|>


<commit_before>#include "p2pclient.h"
#include "utils.h"
#include "crypto/sha2.h"

#include <thread>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

void P2PRelayer::reconnect(std::string disconnectReason, bool alreadyLocked) {
	if (!alreadyLocked)
		send_mutex.lock();

	connected = false;

	if (sock) {
		printf("Closing bitcoind socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
		#ifndef WIN32
			errno = 0;
		#endif
		close(sock);
	}

	send_mutex.unlock();
	sleep(1);
	send_mutex.lock();

	new_thread = new std::thread(do_connect, this);
	send_mutex.unlock();
}

void P2PRelayer::do_connect(P2PRelayer* me) {
	me->send_mutex.lock();

	if (me->net_thread)
		me->net_thread->join();
	me->net_thread = me->new_thread;

	me->sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (me->sock <= 0)
		return me->reconnect("unable to create socket", true);

	sockaddr_in6 addr;
	if (!lookup_address(me->server_host, &addr))
		return me->reconnect("unable to lookup host", true);

	addr.sin6_port = htons(me->server_port);
	if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
		return me->reconnect("failed to connect()", true);

	#ifdef WIN32
		unsigned long nonblocking = 0;
		ioctlsocket(me->sock, FIONBIO, &nonblocking);
	#else
		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);
	#endif

	#ifdef X86_BSD
		int nosigpipe = 1;
		setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
	#endif

	me->net_process();
}

bool P2PRelayer::send_message(const char* command, unsigned char* headerAndData, size_t datalen) {
	prepare_message(command, headerAndData, datalen);
	return send_all(sock, (char*)headerAndData, sizeof(struct bitcoin_msg_header) + datalen) == int(sizeof(struct bitcoin_msg_header) + datalen);
}

void P2PRelayer::net_process() {
	if (!send_version())
		return;

	int nodelay = 1;
	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

	if (errno)
		return reconnect("error during connect", true);

	if (provide_headers) {
		std::vector<unsigned char> msg(sizeof(struct bitcoin_msg_header));
		struct bitcoin_version_start sent_version;
		msg.insert(msg.end(), (unsigned char*)&sent_version.protocol_version, ((unsigned char*)&sent_version.protocol_version) + sizeof(sent_version.protocol_version));
		msg.insert(msg.end(), 1, 1);
		msg.insert(msg.end(), 64, 0);
		send_message("getheaders", &msg[0], msg.size() - sizeof(struct bitcoin_msg_header));
	}

	connected = true;
	send_mutex.unlock();

	while (true) {
		struct bitcoin_msg_header header;
		if (read_all(sock, (char*)&header, sizeof(header)) != sizeof(header))
			return reconnect("failed to read message header");

		if (header.magic != BITCOIN_MAGIC)
			return reconnect("invalid magic bytes");

		header.length = le32toh(header.length);
		if (header.length > 5000000)
			return reconnect("got message too large");

		uint32_t prependedHeaderSize = (!strncmp(header.command, "block", strlen("block"))) ? sizeof(struct bitcoin_msg_header) : 0;

		struct timeval read_start;
		gettimeofday(&read_start, NULL);

		auto msg = std::make_shared<std::vector<unsigned char> > (prependedHeaderSize + uint32_t(header.length));
		if (read_all(sock, (char*)&(*msg)[prependedHeaderSize], header.length) != int(header.length))
			return reconnect("failed to read message");

		unsigned char fullhash[32];
		CSHA256 hash;
		hash.Write(&(*msg)[prependedHeaderSize], header.length).Finalize(fullhash);
		hash.Reset().Write(fullhash, sizeof(fullhash)).Finalize(fullhash);
		if (memcmp((char*)fullhash, header.checksum, sizeof(header.checksum)))
			return reconnect("got invalid message checksum");

		if (!strncmp(header.command, "version", strlen("version"))) {
			if (header.length < sizeof(struct bitcoin_version_start))
				return reconnect("got short version");
			struct bitcoin_version_start *their_version = (struct bitcoin_version_start*) &(*msg)[0];

			printf("Connected to bitcoind with version %u\n", le32toh(their_version->protocol_version));
			struct bitcoin_msg_header new_header;
			send_message("verack", (unsigned char*)&new_header, 0);
		} else if (!strncmp(header.command, "verack", strlen("verack"))) {
			printf("Finished connect handshake with bitcoind\n");
		} else if (!strncmp(header.command, "ping", strlen("ping"))) {
			std::vector<unsigned char> resp(sizeof(struct bitcoin_msg_header) + header.length);
			resp.insert(resp.begin() + sizeof(struct bitcoin_msg_header), msg->begin(), msg->end());
			send_message("pong", &resp[0], header.length);
		} else if (!strncmp(header.command, "inv", strlen("inv"))) {
			std::vector<unsigned char> resp(sizeof(struct bitcoin_msg_header) + header.length);
			resp.insert(resp.begin() + sizeof(struct bitcoin_msg_header), msg->begin(), msg->end());
			send_message("getdata", &resp[0], header.length);
		} else if (!strncmp(header.command, "block", strlen("block"))) {
			provide_block(*msg, read_start);
		} else if (!strncmp(header.command, "tx", strlen("tx"))) {
			provide_transaction(msg);
		} else if (!strncmp(header.command, "headers", strlen("headers"))) {
			if (msg->size() < 82)
				continue; // Probably last one

			if (provide_headers)
				provide_headers(*msg);

			std::vector<unsigned char> req(sizeof(struct bitcoin_msg_header));
			struct bitcoin_version_start sent_version;
			req.insert(req.end(), (unsigned char*)&sent_version.protocol_version, ((unsigned char*)&sent_version.protocol_version) + sizeof(sent_version.protocol_version));
			req.insert(req.end(), 1, 1);

			std::vector<unsigned char> fullhash(32);
			CSHA256 hash;
			hash.Write(&(*msg)[msg->size() - 81], 80).Finalize(&fullhash[0]);
			hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
			req.insert(req.end(), fullhash.begin(), fullhash.end());
			req.insert(req.end(), 32, 0);

			std::lock_guard<std::mutex> lock(send_mutex);
			send_message("getheaders", &req[0], req.size() - sizeof(struct bitcoin_msg_header));
		}
	}
}

void P2PRelayer::receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx) {
	#ifndef FOR_VALGRIND
		if (!send_mutex.try_lock() || !connected)
			return;
	#else
		send_mutex.lock();
	#endif

	auto msg = std::vector<unsigned char>(sizeof(struct bitcoin_msg_header));
	msg.insert(msg.end(), tx->begin(), tx->end());
	send_message("tx", &msg[0], tx->size());

	if (requestAfterSend) {
		std::vector<unsigned char> req(sizeof(struct bitcoin_msg_header));
		req.insert(req.end(), 1, 1);
		uint32_t MSG_TX = htole32(1);
		req.insert(req.end(), (unsigned char*)&MSG_TX, ((unsigned char*)&MSG_TX) + sizeof(MSG_TX));

		std::vector<unsigned char> fullhash(32);
		CSHA256 hash; // Probably not BE-safe
		hash.Write(&(*tx)[0], tx->size()).Finalize(&fullhash[0]);
		hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
		req.insert(req.end(), fullhash.begin(), fullhash.end());

		send_message("getdata", &req[0], 37);
	}

	send_mutex.unlock();
}

void P2PRelayer::receive_block(std::vector<unsigned char>& block) {
	if (!connected)
		return;
	std::lock_guard<std::mutex> lock(send_mutex);
	send_message("block", &block[0], block.size() - sizeof(bitcoin_msg_header));
}

<commit_msg>Fix p2pclient locking<commit_after>#include "p2pclient.h"
#include "utils.h"
#include "crypto/sha2.h"

#include <thread>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

void P2PRelayer::reconnect(std::string disconnectReason, bool alreadyLocked) {
	if (!alreadyLocked)
		send_mutex.lock();

	connected = false;

	if (sock) {
		printf("Closing bitcoind socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
		#ifndef WIN32
			errno = 0;
		#endif
		close(sock);
	}

	send_mutex.unlock();
	sleep(1);
	send_mutex.lock();

	new_thread = new std::thread(do_connect, this);
	send_mutex.unlock();
}

void P2PRelayer::do_connect(P2PRelayer* me) {
	me->send_mutex.lock();

	if (me->net_thread)
		me->net_thread->join();
	me->net_thread = me->new_thread;

	me->sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (me->sock <= 0)
		return me->reconnect("unable to create socket", true);

	sockaddr_in6 addr;
	if (!lookup_address(me->server_host, &addr))
		return me->reconnect("unable to lookup host", true);

	addr.sin6_port = htons(me->server_port);
	if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
		return me->reconnect("failed to connect()", true);

	#ifdef WIN32
		unsigned long nonblocking = 0;
		ioctlsocket(me->sock, FIONBIO, &nonblocking);
	#else
		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);
	#endif

	#ifdef X86_BSD
		int nosigpipe = 1;
		setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
	#endif

	me->net_process();
}

bool P2PRelayer::send_message(const char* command, unsigned char* headerAndData, size_t datalen) {
	prepare_message(command, headerAndData, datalen);
	return send_all(sock, (char*)headerAndData, sizeof(struct bitcoin_msg_header) + datalen) == int(sizeof(struct bitcoin_msg_header) + datalen);
}

void P2PRelayer::net_process() {
	if (!send_version())
		return;

	int nodelay = 1;
	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

	if (errno)
		return reconnect("error during connect", true);

	if (provide_headers) {
		std::vector<unsigned char> msg(sizeof(struct bitcoin_msg_header));
		struct bitcoin_version_start sent_version;
		msg.insert(msg.end(), (unsigned char*)&sent_version.protocol_version, ((unsigned char*)&sent_version.protocol_version) + sizeof(sent_version.protocol_version));
		msg.insert(msg.end(), 1, 1);
		msg.insert(msg.end(), 64, 0);
		send_message("getheaders", &msg[0], msg.size() - sizeof(struct bitcoin_msg_header));
	}

	connected = true;
	send_mutex.unlock();

	while (true) {
		struct bitcoin_msg_header header;
		if (read_all(sock, (char*)&header, sizeof(header)) != sizeof(header))
			return reconnect("failed to read message header");

		if (header.magic != BITCOIN_MAGIC)
			return reconnect("invalid magic bytes");

		header.length = le32toh(header.length);
		if (header.length > 5000000)
			return reconnect("got message too large");

		uint32_t prependedHeaderSize = (!strncmp(header.command, "block", strlen("block"))) ? sizeof(struct bitcoin_msg_header) : 0;

		struct timeval read_start;
		gettimeofday(&read_start, NULL);

		auto msg = std::make_shared<std::vector<unsigned char> > (prependedHeaderSize + uint32_t(header.length));
		if (read_all(sock, (char*)&(*msg)[prependedHeaderSize], header.length) != int(header.length))
			return reconnect("failed to read message");

		unsigned char fullhash[32];
		CSHA256 hash;
		hash.Write(&(*msg)[prependedHeaderSize], header.length).Finalize(fullhash);
		hash.Reset().Write(fullhash, sizeof(fullhash)).Finalize(fullhash);
		if (memcmp((char*)fullhash, header.checksum, sizeof(header.checksum)))
			return reconnect("got invalid message checksum");

		if (!strncmp(header.command, "version", strlen("version"))) {
			if (header.length < sizeof(struct bitcoin_version_start))
				return reconnect("got short version");
			struct bitcoin_version_start *their_version = (struct bitcoin_version_start*) &(*msg)[0];

			printf("Connected to bitcoind with version %u\n", le32toh(their_version->protocol_version));
			struct bitcoin_msg_header new_header;
			send_message("verack", (unsigned char*)&new_header, 0);
		} else if (!strncmp(header.command, "verack", strlen("verack"))) {
			printf("Finished connect handshake with bitcoind\n");
		} else if (!strncmp(header.command, "ping", strlen("ping"))) {
			std::vector<unsigned char> resp(sizeof(struct bitcoin_msg_header) + header.length);
			resp.insert(resp.begin() + sizeof(struct bitcoin_msg_header), msg->begin(), msg->end());
			send_message("pong", &resp[0], header.length);
		} else if (!strncmp(header.command, "inv", strlen("inv"))) {
			std::vector<unsigned char> resp(sizeof(struct bitcoin_msg_header) + header.length);
			resp.insert(resp.begin() + sizeof(struct bitcoin_msg_header), msg->begin(), msg->end());
			send_message("getdata", &resp[0], header.length);
		} else if (!strncmp(header.command, "block", strlen("block"))) {
			provide_block(*msg, read_start);
		} else if (!strncmp(header.command, "tx", strlen("tx"))) {
			provide_transaction(msg);
		} else if (!strncmp(header.command, "headers", strlen("headers"))) {
			if (msg->size() < 82)
				continue; // Probably last one

			if (provide_headers)
				provide_headers(*msg);

			std::vector<unsigned char> req(sizeof(struct bitcoin_msg_header));
			struct bitcoin_version_start sent_version;
			req.insert(req.end(), (unsigned char*)&sent_version.protocol_version, ((unsigned char*)&sent_version.protocol_version) + sizeof(sent_version.protocol_version));
			req.insert(req.end(), 1, 1);

			std::vector<unsigned char> fullhash(32);
			CSHA256 hash;
			hash.Write(&(*msg)[msg->size() - 81], 80).Finalize(&fullhash[0]);
			hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
			req.insert(req.end(), fullhash.begin(), fullhash.end());
			req.insert(req.end(), 32, 0);

			std::lock_guard<std::mutex> lock(send_mutex);
			send_message("getheaders", &req[0], req.size() - sizeof(struct bitcoin_msg_header));
		}
	}
}

void P2PRelayer::receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx) {
	#ifndef FOR_VALGRIND
		if (!send_mutex.try_lock())
			return;
	#else
		send_mutex.lock();
	#endif

	if (!connected) {
		send_mutex.unlock();
		return;
	}

	auto msg = std::vector<unsigned char>(sizeof(struct bitcoin_msg_header));
	msg.insert(msg.end(), tx->begin(), tx->end());
	send_message("tx", &msg[0], tx->size());

	if (requestAfterSend) {
		std::vector<unsigned char> req(sizeof(struct bitcoin_msg_header));
		req.insert(req.end(), 1, 1);
		uint32_t MSG_TX = htole32(1);
		req.insert(req.end(), (unsigned char*)&MSG_TX, ((unsigned char*)&MSG_TX) + sizeof(MSG_TX));

		std::vector<unsigned char> fullhash(32);
		CSHA256 hash; // Probably not BE-safe
		hash.Write(&(*tx)[0], tx->size()).Finalize(&fullhash[0]);
		hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
		req.insert(req.end(), fullhash.begin(), fullhash.end());

		send_message("getdata", &req[0], 37);
	}

	send_mutex.unlock();
}

void P2PRelayer::receive_block(std::vector<unsigned char>& block) {
	std::lock_guard<std::mutex> lock(send_mutex);
	if (!connected)
		return;
	send_message("block", &block[0], block.size() - sizeof(bitcoin_msg_header));
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "io.h"
#include "debug.h"
#include <unistd.h>
#include <sys/uio.h>
#include <algorithm>
#include <errno.h>

namespace kj {

InputStream::~InputStream() noexcept(false) {}
OutputStream::~OutputStream() noexcept(false) {}
BufferedInputStream::~BufferedInputStream() noexcept(false) {}
BufferedOutputStream::~BufferedOutputStream() noexcept(false) {}

size_t InputStream::read(void* buffer, size_t minBytes, size_t maxBytes) {
  size_t n = tryRead(buffer, minBytes, maxBytes);
  KJ_REQUIRE(n >= minBytes, "Premature EOF") {
    // Pretend we read zeros from the input.
    memset(reinterpret_cast<byte*>(buffer) + n, 0, minBytes - n);
    return minBytes;
  }
  return n;
}

void InputStream::skip(size_t bytes) {
  char scratch[8192];
  while (bytes > 0) {
    size_t amount = std::min(bytes, sizeof(scratch));
    read(scratch, amount);
    bytes -= amount;
  }
}

void OutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  for (auto piece: pieces) {
    write(piece.begin(), piece.size());
  }
}

ArrayPtr<const byte> BufferedInputStream::getReadBuffer() {
  auto result = tryGetReadBuffer();
  KJ_REQUIRE(result.size() > 0, "Premature EOF");
  return result;
}

// =======================================================================================

BufferedInputStreamWrapper::BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner), ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer) {}

BufferedInputStreamWrapper::~BufferedInputStreamWrapper() noexcept(false) {}

ArrayPtr<const byte> BufferedInputStreamWrapper::tryGetReadBuffer() {
  if (bufferAvailable.size() == 0) {
    size_t n = inner.tryRead(buffer.begin(), 1, buffer.size());
    bufferAvailable = buffer.slice(0, n);
  }

  return bufferAvailable;
}

size_t BufferedInputStreamWrapper::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  if (minBytes <= bufferAvailable.size()) {
    // Serve from current buffer.
    size_t n = std::min(bufferAvailable.size(), maxBytes);
    memcpy(dst, bufferAvailable.begin(), n);
    bufferAvailable = bufferAvailable.slice(n, bufferAvailable.size());
    return n;
  } else {
    // Copy current available into destination.
    memcpy(dst, bufferAvailable.begin(), bufferAvailable.size());
    size_t fromFirstBuffer = bufferAvailable.size();

    dst = reinterpret_cast<byte*>(dst) + fromFirstBuffer;
    minBytes -= fromFirstBuffer;
    maxBytes -= fromFirstBuffer;

    if (maxBytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), minBytes, buffer.size());
      size_t fromSecondBuffer = std::min(n, maxBytes);
      memcpy(dst, buffer.begin(), fromSecondBuffer);
      bufferAvailable = buffer.slice(fromSecondBuffer, n);
      return fromFirstBuffer + fromSecondBuffer;
    } else {
      // Forward large read to the underlying stream.
      bufferAvailable = nullptr;
      return fromFirstBuffer + inner.read(dst, minBytes, maxBytes);
    }
  }
}

void BufferedInputStreamWrapper::skip(size_t bytes) {
  if (bytes <= bufferAvailable.size()) {
    bufferAvailable = bufferAvailable.slice(bytes, bufferAvailable.size());
  } else {
    bytes -= bufferAvailable.size();
    if (bytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), bytes, buffer.size());
      bufferAvailable = buffer.slice(bytes, n);
    } else {
      // Forward large skip to the underlying stream.
      bufferAvailable = nullptr;
      inner.skip(bytes - bufferAvailable.size());
    }
  }
}

// -------------------------------------------------------------------

BufferedOutputStreamWrapper::BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner),
      ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer),
      bufferPos(this->buffer.begin()) {}

BufferedOutputStreamWrapper::~BufferedOutputStreamWrapper() noexcept(false) {
  unwindDetector.catchExceptionsIfUnwinding([&]() {
    flush();
  });
}

void BufferedOutputStreamWrapper::flush() {
  if (bufferPos > buffer.begin()) {
    inner.write(buffer.begin(), bufferPos - buffer.begin());
    bufferPos = buffer.begin();
  }
}

ArrayPtr<byte> BufferedOutputStreamWrapper::getWriteBuffer() {
  return arrayPtr(bufferPos, buffer.end());
}

void BufferedOutputStreamWrapper::write(const void* src, size_t size) {
  if (src == bufferPos) {
    // Oh goody, the caller wrote directly into our buffer.
    bufferPos += size;
  } else {
    size_t available = buffer.end() - bufferPos;

    if (size <= available) {
      memcpy(bufferPos, src, size);
      bufferPos += size;
    } else if (size <= buffer.size()) {
      // Too much for this buffer, but not a full buffer's worth, so we'll go ahead and copy.
      memcpy(bufferPos, src, available);
      inner.write(buffer.begin(), buffer.size());

      size -= available;
      src = reinterpret_cast<const byte*>(src) + available;

      memcpy(buffer.begin(), src, size);
      bufferPos = buffer.begin() + size;
    } else {
      // Writing so much data that we might as well write directly to avoid a copy.
      inner.write(buffer.begin(), bufferPos - buffer.begin());
      bufferPos = buffer.begin();
      inner.write(src, size);
    }
  }
}

// =======================================================================================

ArrayInputStream::ArrayInputStream(ArrayPtr<const byte> array): array(array) {}
ArrayInputStream::~ArrayInputStream() noexcept(false) {}

ArrayPtr<const byte> ArrayInputStream::tryGetReadBuffer() {
  return array;
}

size_t ArrayInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  size_t n = std::min(maxBytes, array.size());
  memcpy(dst, array.begin(), n);
  array = array.slice(n, array.size());
  return n;
}

void ArrayInputStream::skip(size_t bytes) {
  KJ_REQUIRE(array.size() >= bytes, "ArrayInputStream ended prematurely.") {
    bytes = array.size();
    break;
  }
  array = array.slice(bytes, array.size());
}

// -------------------------------------------------------------------

ArrayOutputStream::ArrayOutputStream(ArrayPtr<byte> array): array(array), fillPos(array.begin()) {}
ArrayOutputStream::~ArrayOutputStream() noexcept(false) {}

ArrayPtr<byte> ArrayOutputStream::getWriteBuffer() {
  return arrayPtr(fillPos, array.end());
}

void ArrayOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    fillPos += size;
  } else {
    KJ_REQUIRE(size <= (size_t)(array.end() - fillPos),
            "ArrayOutputStream's backing array was not large enough for the data written.");
    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

// =======================================================================================

AutoCloseFd::~AutoCloseFd() noexcept(false) {
  if (fd >= 0) {
    unwindDetector.catchExceptionsIfUnwinding([&]() {
      // Don't use SYSCALL() here because close() should not be repeated on EINTR.
      if (close(fd) < 0) {
        KJ_FAIL_SYSCALL("close", errno, fd) {
          break;
        }
      }
    });
  }
}

FdInputStream::~FdInputStream() noexcept(false) {}

size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
  byte* pos = reinterpret_cast<byte*>(buffer);
  byte* min = pos + minBytes;
  byte* max = pos + maxBytes;

  while (pos < min) {
    ssize_t n;
    KJ_SYSCALL(n = ::read(fd, pos, max - pos), fd);
    if (n == 0) {
      break;
    }
    pos += n;
  }

  return pos - reinterpret_cast<byte*>(buffer);
}

FdOutputStream::~FdOutputStream() noexcept(false) {}

void FdOutputStream::write(const void* buffer, size_t size) {
  const char* pos = reinterpret_cast<const char*>(buffer);

  while (size > 0) {
    ssize_t n;
    KJ_SYSCALL(n = ::write(fd, pos, size), fd);
    KJ_ASSERT(n > 0, "write() returned zero.");
    pos += n;
    size -= n;
  }
}

void FdOutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  // Apparently, there is a maximum number of iovecs allowed per call.  I don't understand why.
  // Also, most platforms define IOV_MAX but Linux defines only UIO_MAXIOV.  Unfortunately, Solaris
  // defines a constant UIO_MAXIOV with a different meaning, so we check for IOV_MAX first.
#if !defined(IOV_MAX) && defined(UIO_MAXIOV)
#define IOV_MAX UIO_MAXIOV
#endif
  while (pieces.size() > IOV_MAX) {
    write(pieces.slice(0, IOV_MAX));
    pieces = pieces.slice(IOV_MAX, pieces.size());
  }

  KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128);

  for (uint i = 0; i < pieces.size(); i++) {
    // writev() interface is not const-correct.  :(
    iov[i].iov_base = const_cast<byte*>(pieces[i].begin());
    iov[i].iov_len = pieces[i].size();
  }

  struct iovec* current = iov.begin();

  // Make sure we don't do anything on an empty write.
  while (current < iov.end() && current->iov_len == 0) {
    ++current;
  }

  while (current < iov.end()) {
    ssize_t n = 0;
    KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd);
    KJ_ASSERT(n > 0, "writev() returned zero.");

    while (n > 0 && static_cast<size_t>(n) >= current->iov_len) {
      n -= current->iov_len;
      ++current;
    }

    if (n > 0) {
      current->iov_base = reinterpret_cast<byte*>(current->iov_base) + n;
      current->iov_len -= n;
    }
  }
}

}  // namespace kj
<commit_msg>Add missing include for OSX.<commit_after>// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "io.h"
#include "debug.h"
#include <unistd.h>
#include <sys/uio.h>
#include <algorithm>
#include <errno.h>
#include <limits.h>

namespace kj {

InputStream::~InputStream() noexcept(false) {}
OutputStream::~OutputStream() noexcept(false) {}
BufferedInputStream::~BufferedInputStream() noexcept(false) {}
BufferedOutputStream::~BufferedOutputStream() noexcept(false) {}

size_t InputStream::read(void* buffer, size_t minBytes, size_t maxBytes) {
  size_t n = tryRead(buffer, minBytes, maxBytes);
  KJ_REQUIRE(n >= minBytes, "Premature EOF") {
    // Pretend we read zeros from the input.
    memset(reinterpret_cast<byte*>(buffer) + n, 0, minBytes - n);
    return minBytes;
  }
  return n;
}

void InputStream::skip(size_t bytes) {
  char scratch[8192];
  while (bytes > 0) {
    size_t amount = std::min(bytes, sizeof(scratch));
    read(scratch, amount);
    bytes -= amount;
  }
}

void OutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  for (auto piece: pieces) {
    write(piece.begin(), piece.size());
  }
}

ArrayPtr<const byte> BufferedInputStream::getReadBuffer() {
  auto result = tryGetReadBuffer();
  KJ_REQUIRE(result.size() > 0, "Premature EOF");
  return result;
}

// =======================================================================================

BufferedInputStreamWrapper::BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner), ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer) {}

BufferedInputStreamWrapper::~BufferedInputStreamWrapper() noexcept(false) {}

ArrayPtr<const byte> BufferedInputStreamWrapper::tryGetReadBuffer() {
  if (bufferAvailable.size() == 0) {
    size_t n = inner.tryRead(buffer.begin(), 1, buffer.size());
    bufferAvailable = buffer.slice(0, n);
  }

  return bufferAvailable;
}

size_t BufferedInputStreamWrapper::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  if (minBytes <= bufferAvailable.size()) {
    // Serve from current buffer.
    size_t n = std::min(bufferAvailable.size(), maxBytes);
    memcpy(dst, bufferAvailable.begin(), n);
    bufferAvailable = bufferAvailable.slice(n, bufferAvailable.size());
    return n;
  } else {
    // Copy current available into destination.
    memcpy(dst, bufferAvailable.begin(), bufferAvailable.size());
    size_t fromFirstBuffer = bufferAvailable.size();

    dst = reinterpret_cast<byte*>(dst) + fromFirstBuffer;
    minBytes -= fromFirstBuffer;
    maxBytes -= fromFirstBuffer;

    if (maxBytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), minBytes, buffer.size());
      size_t fromSecondBuffer = std::min(n, maxBytes);
      memcpy(dst, buffer.begin(), fromSecondBuffer);
      bufferAvailable = buffer.slice(fromSecondBuffer, n);
      return fromFirstBuffer + fromSecondBuffer;
    } else {
      // Forward large read to the underlying stream.
      bufferAvailable = nullptr;
      return fromFirstBuffer + inner.read(dst, minBytes, maxBytes);
    }
  }
}

void BufferedInputStreamWrapper::skip(size_t bytes) {
  if (bytes <= bufferAvailable.size()) {
    bufferAvailable = bufferAvailable.slice(bytes, bufferAvailable.size());
  } else {
    bytes -= bufferAvailable.size();
    if (bytes <= buffer.size()) {
      // Read the next buffer-full.
      size_t n = inner.read(buffer.begin(), bytes, buffer.size());
      bufferAvailable = buffer.slice(bytes, n);
    } else {
      // Forward large skip to the underlying stream.
      bufferAvailable = nullptr;
      inner.skip(bytes - bufferAvailable.size());
    }
  }
}

// -------------------------------------------------------------------

BufferedOutputStreamWrapper::BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer)
    : inner(inner),
      ownedBuffer(buffer == nullptr ? heapArray<byte>(8192) : nullptr),
      buffer(buffer == nullptr ? ownedBuffer : buffer),
      bufferPos(this->buffer.begin()) {}

BufferedOutputStreamWrapper::~BufferedOutputStreamWrapper() noexcept(false) {
  unwindDetector.catchExceptionsIfUnwinding([&]() {
    flush();
  });
}

void BufferedOutputStreamWrapper::flush() {
  if (bufferPos > buffer.begin()) {
    inner.write(buffer.begin(), bufferPos - buffer.begin());
    bufferPos = buffer.begin();
  }
}

ArrayPtr<byte> BufferedOutputStreamWrapper::getWriteBuffer() {
  return arrayPtr(bufferPos, buffer.end());
}

void BufferedOutputStreamWrapper::write(const void* src, size_t size) {
  if (src == bufferPos) {
    // Oh goody, the caller wrote directly into our buffer.
    bufferPos += size;
  } else {
    size_t available = buffer.end() - bufferPos;

    if (size <= available) {
      memcpy(bufferPos, src, size);
      bufferPos += size;
    } else if (size <= buffer.size()) {
      // Too much for this buffer, but not a full buffer's worth, so we'll go ahead and copy.
      memcpy(bufferPos, src, available);
      inner.write(buffer.begin(), buffer.size());

      size -= available;
      src = reinterpret_cast<const byte*>(src) + available;

      memcpy(buffer.begin(), src, size);
      bufferPos = buffer.begin() + size;
    } else {
      // Writing so much data that we might as well write directly to avoid a copy.
      inner.write(buffer.begin(), bufferPos - buffer.begin());
      bufferPos = buffer.begin();
      inner.write(src, size);
    }
  }
}

// =======================================================================================

ArrayInputStream::ArrayInputStream(ArrayPtr<const byte> array): array(array) {}
ArrayInputStream::~ArrayInputStream() noexcept(false) {}

ArrayPtr<const byte> ArrayInputStream::tryGetReadBuffer() {
  return array;
}

size_t ArrayInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
  size_t n = std::min(maxBytes, array.size());
  memcpy(dst, array.begin(), n);
  array = array.slice(n, array.size());
  return n;
}

void ArrayInputStream::skip(size_t bytes) {
  KJ_REQUIRE(array.size() >= bytes, "ArrayInputStream ended prematurely.") {
    bytes = array.size();
    break;
  }
  array = array.slice(bytes, array.size());
}

// -------------------------------------------------------------------

ArrayOutputStream::ArrayOutputStream(ArrayPtr<byte> array): array(array), fillPos(array.begin()) {}
ArrayOutputStream::~ArrayOutputStream() noexcept(false) {}

ArrayPtr<byte> ArrayOutputStream::getWriteBuffer() {
  return arrayPtr(fillPos, array.end());
}

void ArrayOutputStream::write(const void* src, size_t size) {
  if (src == fillPos) {
    // Oh goody, the caller wrote directly into our buffer.
    fillPos += size;
  } else {
    KJ_REQUIRE(size <= (size_t)(array.end() - fillPos),
            "ArrayOutputStream's backing array was not large enough for the data written.");
    memcpy(fillPos, src, size);
    fillPos += size;
  }
}

// =======================================================================================

AutoCloseFd::~AutoCloseFd() noexcept(false) {
  if (fd >= 0) {
    unwindDetector.catchExceptionsIfUnwinding([&]() {
      // Don't use SYSCALL() here because close() should not be repeated on EINTR.
      if (close(fd) < 0) {
        KJ_FAIL_SYSCALL("close", errno, fd) {
          break;
        }
      }
    });
  }
}

FdInputStream::~FdInputStream() noexcept(false) {}

size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
  byte* pos = reinterpret_cast<byte*>(buffer);
  byte* min = pos + minBytes;
  byte* max = pos + maxBytes;

  while (pos < min) {
    ssize_t n;
    KJ_SYSCALL(n = ::read(fd, pos, max - pos), fd);
    if (n == 0) {
      break;
    }
    pos += n;
  }

  return pos - reinterpret_cast<byte*>(buffer);
}

FdOutputStream::~FdOutputStream() noexcept(false) {}

void FdOutputStream::write(const void* buffer, size_t size) {
  const char* pos = reinterpret_cast<const char*>(buffer);

  while (size > 0) {
    ssize_t n;
    KJ_SYSCALL(n = ::write(fd, pos, size), fd);
    KJ_ASSERT(n > 0, "write() returned zero.");
    pos += n;
    size -= n;
  }
}

void FdOutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
  // Apparently, there is a maximum number of iovecs allowed per call.  I don't understand why.
  // Also, most platforms define IOV_MAX but Linux defines only UIO_MAXIOV.  Unfortunately, Solaris
  // defines a constant UIO_MAXIOV with a different meaning, so we check for IOV_MAX first.
#if !defined(IOV_MAX) && defined(UIO_MAXIOV)
#define IOV_MAX UIO_MAXIOV
#endif
  while (pieces.size() > IOV_MAX) {
    write(pieces.slice(0, IOV_MAX));
    pieces = pieces.slice(IOV_MAX, pieces.size());
  }

  KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128);

  for (uint i = 0; i < pieces.size(); i++) {
    // writev() interface is not const-correct.  :(
    iov[i].iov_base = const_cast<byte*>(pieces[i].begin());
    iov[i].iov_len = pieces[i].size();
  }

  struct iovec* current = iov.begin();

  // Make sure we don't do anything on an empty write.
  while (current < iov.end() && current->iov_len == 0) {
    ++current;
  }

  while (current < iov.end()) {
    ssize_t n = 0;
    KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd);
    KJ_ASSERT(n > 0, "writev() returned zero.");

    while (n > 0 && static_cast<size_t>(n) >= current->iov_len) {
      n -= current->iov_len;
      ++current;
    }

    if (n > 0) {
      current->iov_base = reinterpret_cast<byte*>(current->iov_base) + n;
      current->iov_len -= n;
    }
  }
}

}  // namespace kj
<|endoftext|>


<commit_before>
#include "geom.hh"
#include "iterator.hh"

namespace Topo {

Geo::Point face_normal(Topo::Wrap<Topo::Type::FACE> _face)
{
  Iterator<Type::FACE, Type::VERTEX> fv_it;
  std::vector<Geo::Point> verts;
  for (auto vert : fv_it)
  {
    verts.emplace_back();
    vert->geom(verts.back());
  }
  auto poly_face = Geo::IPolygonalFace::make(verts.begin(), verts.end());
  return poly_face->normal();
}

Geo::Point coedge_direction(Topo::Wrap<Topo::Type::COEDGE> _coed)
{
  Geo::Segment seg;
  _coed->geom(seg);
  return seg[1] - seg[0];
}

}//namespace Topo<commit_msg>fIX BUG TOMAKE SELECTION WORK.<commit_after>
#include "geom.hh"
#include "iterator.hh"

namespace Topo {

Geo::Point face_normal(Topo::Wrap<Topo::Type::FACE> _face)
{
  Iterator<Type::FACE, Type::VERTEX> fv_it(_face);
  std::vector<Geo::Point> verts;
  for (auto vert : fv_it)
  {
    verts.emplace_back();
    vert->geom(verts.back());
  }
  auto poly_face = Geo::IPolygonalFace::make(verts.begin(), verts.end());
  return poly_face->normal();
}

Geo::Point coedge_direction(Topo::Wrap<Topo::Type::COEDGE> _coed)
{
  Geo::Segment seg;
  _coed->geom(seg);
  return seg[1] - seg[0];
}

}//namespace Topo<|endoftext|>


<commit_before><commit_msg>10827 - Maximum sum on a torus<commit_after><|endoftext|>


<commit_before>#pragma once

#include "../indexer/feature.hpp"
#include "../indexer/features_vector.hpp"
#include "../indexer/index.hpp"

#include "../geometry/rect2d.hpp"
#include "../geometry/point2d.hpp"

#include "../coding/file_reader.hpp"
#include "../coding/buffer_reader.hpp"

#include "../base/start_mem_debug.hpp"

namespace model
{
//#define USE_BUFFER_READER

  class FeaturesFetcher
  {
  public:
#ifdef USE_BUFFER_READER
    typedef BufferReader ReaderT;
#else
    typedef ModelReaderPtr ReaderT;
#endif

  private:
    m2::RectD m_rect;

    typedef Index<ReaderT>::Type index_t;

    index_t m_multiIndex;

    // Cached query, which stores several caches for the index.
    mutable index_t::Query m_multiIndexQuery;

  public:
    void InitClassificator();

    void AddMap(string const & file);
    void RemoveMap(string const & fName);
    void Clean();
    void ClearCaches();

    // process features by param type indices
    template <class ToDo>
    void ForEachFeature(m2::RectD const & rect, ToDo toDo) const
    {
      m_multiIndexQuery.Clear();
      m_multiIndex.ForEachInViewport(toDo, rect, m_multiIndexQuery);
      // Uncomment to traverse all features (SLOW!!):
      // m_multiIndex.ForEachInScale(toDo, GetScaleLevel(rect));
    }

    template <class ToDo>
    void ForEachFeatureWithScale(m2::RectD const & rect, ToDo toDo, int scale) const
    {
      m_multiIndex.ForEachInRect(toDo, rect, scale);
    }

    index_t const & GetIndex() const { return m_multiIndex; }

    void AddWorldRect(m2::RectD const & r) { m_rect.Add(r); }
    m2::RectD GetWorldRect() const;
  };
}

#include "../base/stop_mem_debug.hpp"
<commit_msg>Remove mutable cached query from FeaturesFetcher.<commit_after>#pragma once

#include "../indexer/feature.hpp"
#include "../indexer/features_vector.hpp"
#include "../indexer/index.hpp"

#include "../geometry/rect2d.hpp"
#include "../geometry/point2d.hpp"

#include "../coding/file_reader.hpp"
#include "../coding/buffer_reader.hpp"

#include "../base/start_mem_debug.hpp"

namespace model
{
//#define USE_BUFFER_READER

  class FeaturesFetcher
  {
  public:
#ifdef USE_BUFFER_READER
    typedef BufferReader ReaderT;
#else
    typedef ModelReaderPtr ReaderT;
#endif

  private:
    m2::RectD m_rect;

    typedef Index<ReaderT>::Type index_t;

    index_t m_multiIndex;

  public:
    void InitClassificator();

    void AddMap(string const & file);
    void RemoveMap(string const & fName);
    void Clean();
    void ClearCaches();

    // process features by param type indices
    template <class ToDo>
    void ForEachFeature(m2::RectD const & rect, ToDo toDo) const
    {
      index_t::Query query;
      m_multiIndex.ForEachInViewport(toDo, rect, query);
      // Uncomment to traverse all features (SLOW!!):
      // m_multiIndex.ForEachInScale(toDo, GetScaleLevel(rect));
    }

    template <class ToDo>
    void ForEachFeatureWithScale(m2::RectD const & rect, ToDo toDo, int scale) const
    {
      m_multiIndex.ForEachInRect(toDo, rect, scale);
    }

    index_t const & GetIndex() const { return m_multiIndex; }

    void AddWorldRect(m2::RectD const & r) { m_rect.Add(r); }
    m2::RectD GetWorldRect() const;
  };
}

#include "../base/stop_mem_debug.hpp"
<|endoftext|>


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

#include "stdafx.h"

#include "NativeTabbar.h"
#include "MainWindow.h"
#include "rubyext/WebView.h"
#include "json/JSONIterator.h"

IMPLEMENT_LOGCLASS(CNativeTabbar,"NativeTabbar");

extern CMainWindow& getAppWindow();

using namespace rho::json;

CNativeTabbar::CNativeTabbar()
{
    m_nCurrentTab = -1;
    m_bTabCreated = false;
}

static int getColorFromString(const char* szColor)
{
    if ( !szColor || !*szColor )
        return RGB(0, 0, 0);

	int c = atoi(szColor);

	int cR = (c & 0xFF0000) >> 16;
	int cG = (c & 0xFF00) >> 8;
	int cB = (c & 0xFF);

    return RGB(cR, cG, cB);
}

void CNativeTabbar::CreateTabbarEx(const rho::Vector<rho::String>& tabbarElements, const rho::Hashtable<rho::String, rho::String>& tabBarProperties, rho::apiGenerator::CMethodResult& oResult)
{
    if (!rho_rhodesapp_check_mode() )
        return;

    RemoveTabbar();

	COLORREF   rgbBackColor;
    bool bHiddenTabs = false, bCreateOnInit = false;

    for ( Hashtable<rho::String, rho::String>::const_iterator it = tabBarProperties.begin(); it != tabBarProperties.end(); ++it )
    {
        const char *name = (it->first).c_str();
        const char *value = (it->second).c_str();
        if (strcasecmp(name, "backgroundColor") == 0)
            rgbBackColor = getColorFromString(value);
        if (strcasecmp(name, "hiddenTabs") == 0)
            bHiddenTabs = strcasecmp(value, "true") == 0;
        if (strcasecmp(name, "createOnInit") == 0)
            bCreateOnInit = strcasecmp(value, "true") == 0;

    }

    if ( !bHiddenTabs )
    {
        LOG(WARNING) + "Illegal argument for create_nativebar: hiddenTabs should be true for Windows Mobile and Windows CE.";
        bHiddenTabs = true;
    }

    int nStartTab = -1;

    for (int i = 0; i < (int)tabbarElements.size(); ++i)
    {
        const char *label = NULL;
        const char *action = NULL;
        const char *icon = NULL;
        const char *reload = NULL;
        const char *colored_icon = NULL;

    	COLORREF selected_color;
        const char *disabled = NULL;
		COLORREF web_bkg_color;
        const char* use_current_view_for_tab = NULL;
        bool bUseCurrentViewForTab = false, bReloadPage = false, bPerishable = false, bCreateOnInitTab = false;
        CJSONEntry oEntry(tabbarElements[i].c_str());

        if ( oEntry.hasName("label") )
            label = oEntry.getString("label");
        if ( oEntry.hasName("action") )
            action = oEntry.getString("action");
        if ( oEntry.hasName("icon") )
            icon = oEntry.getString("icon");
        if ( oEntry.hasName("coloredIcon") )
            colored_icon = oEntry.getString("coloredIcon");
        if ( oEntry.hasName("reload") )
        {
            reload = oEntry.getString("reload");
            if (strcasecmp(reload, "true") == 0)
                bReloadPage = true;
        }
        if ( oEntry.hasName("perishable") )
        {
            const char* perishable = oEntry.getString("perishable");
            if (strcasecmp(perishable, "true") == 0)
                bPerishable = true;
        }
        if ( oEntry.hasName("createOnInit") )
        {
            const char* createOnInit = oEntry.getString("createOnInit");
            if (strcasecmp(createOnInit, "true") == 0)
                bCreateOnInitTab = true;
        }

        if ( oEntry.hasName("selectedColor") )
            selected_color = getColorFromString(oEntry.getString("selectedColor"));
        if ( oEntry.hasName("disabled") )
            disabled = oEntry.getString("disabled");
        if ( oEntry.hasName("useCurrentViewForTab") )
        {
            use_current_view_for_tab = oEntry.getString("useCurrentViewForTab");
            if (strcasecmp(use_current_view_for_tab, "true") == 0)
                bUseCurrentViewForTab = true;
        }
        if (oEntry.hasName("backgroundColor"))
            web_bkg_color = getColorFromString(oEntry.getString("backgroundColor"));

        if (label == NULL)
            label = "";
        if (action == NULL)
            action = "";

        m_arTabs.addElement(CTabBarItem(action, label, bUseCurrentViewForTab, bReloadPage, bPerishable, bCreateOnInitTab));

        if (m_strStartTabName.length()>0 && m_strStartTabName == label)
            nStartTab = i;

    }

    if ( oResult.hasCallback() )
        m_oCallback = oResult;

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_bCreateOnInit || bCreateOnInit )
            SwitchTab(i, true);
    }

    if (m_strStartTabName.length()>0&&nStartTab>=0)
    {
        //getAppWindow().SetTimer( TABBAR_TIMER_ID, 1000 );
        SwitchTabByName( m_strStartTabName.c_str(), false );
        m_strStartTabName = "";
    }else if ( m_arTabs.size() ) //&& !m_arTabs[0].m_bUseCurrentViewForTab )
        SwitchTab(0);

    m_bTabCreated = true;
}

LRESULT CNativeTabbar::OnTimer (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SwitchTabByName( m_strStartTabName.c_str(), false );
    m_strStartTabName = "";
    getAppWindow().KillTimer( TABBAR_TIMER_ID );

    return 0;
}

void CNativeTabbar::RemoveTabbar()
{
    getAppWindow().getWebKitEngine()->SwitchTab(0); //Switch to main view

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if (m_arTabs[i].m_nTabID > 0 ) //do not remove tab 0
            getAppWindow().getWebKitEngine()->CloseTab(m_arTabs[i].m_nTabID);
    }

    m_arTabs.removeAllElements();
    m_bTabCreated = false;
    m_nCurrentTab = -1;
}

void CNativeTabbar::RemoveTab(int index)
{
    if (index >= 0 && index < (int)m_arTabs.size() )
    {
        if (m_arTabs[index].m_nTabID > 0 ) //do not remove tab 0
        {
            LOG(INFO) + "Close Tab: " + index;
            getAppWindow().getWebKitEngine()->CloseTab(m_arTabs[index].m_nTabID);

            m_arTabs[index].m_nTabID = -1;
            m_arTabs[index].m_hwndTab = 0;
        }
    }
}

void CNativeTabbar::SwitchTabByName(const char* szTabName, bool bExecuteJS)
{
    LOG(INFO) + "tabbarSwitchByName: " + szTabName;

    if ( !szTabName || !*szTabName)
        return;

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_strLabel == szTabName )
        {
            /*if ( bExecuteJS )
            {
                String strJS = "Rho.NativeTabbar.switchTab(";
                strJS += convertToStringA(i);
                strJS += ");";

                rho_webview_execute_js( strJS.c_str(), GetCurrentTabIndex() );
            }
            else*/
                SwitchTab(i, false, true);
            break;
        }
    }
}

void CNativeTabbar::raiseTabEvent( const char* szEventName, int nOldTab, int nNewTab )
{
    if ( m_oCallback.hasCallback() )
    {
        LOG(INFO) + "raiseTabEvent: " + szEventName + "; " + nOldTab + "; " + nNewTab;

        Hashtable<String,String> mapRes;
        mapRes["tab_index"] = convertToStringA(nNewTab);
        mapRes["newTabIndex"] = convertToStringA(nNewTab);
        mapRes["oldTabIndex"] = convertToStringA(nOldTab);
        mapRes["tabEvent"] = szEventName;
        m_oCallback.set(mapRes);
    }
}

//as Newtab is a blocking function we have a timeout.
#define NEWTAB_IPC_ERR	-1
#define NEWTAB_TIMEOUT	-2	// the new tab call timed out
#define NEWTAB_LOW_MEM	-3 // A tab cannot be created due to hitting the memory limit m_iMemLimit
#define NEWTAB_MAX_TABS -4 // we have hit the #defined max tabs value defined in Engine2Core; MAX_TABS

bool CNativeTabbar::removePerishableTab()
{
    int nTabToClose = -1;
    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_nTabID > 0 && m_arTabs[i].m_bPerishable && i != m_nCurrentTab )
        {
            nTabToClose = i;
            break;
        }
    }

    if ( nTabToClose == -1 && m_nCurrentTab > 0 )
        nTabToClose = m_nCurrentTab;

    if ( nTabToClose == -1 )
        return false;

    RemoveTab(nTabToClose);
    return true;
}

void CNativeTabbar::SwitchTab(int index, bool bCreateOnly/*=false*/, bool bByName /*= false*/)
{
    if (!getAppWindow().getWebKitEngine())
        return;

    if (( index >= (int)m_arTabs.size() )||(index<0))
    {
        LOG(ERROR) + "Invalid Tab Index: " + index;
        return;
    }

    bool bNewTab = !m_arTabs[index].m_hwndTab;
    if ( !m_arTabs[index].m_hwndTab )
    {
        if ( m_arTabs[index].m_bUseCurrentViewForTab)
        {
            m_arTabs[index].m_nTabID = 0;
            m_arTabs[index].m_hwndTab = getAppWindow().getWebKitEngine()->GetHTMLWND(0);

            bNewTab = false;
        }else
        {
            //raiseTabEvent( "onTabNewRequest", m_nCurrentTab, -1 );

            m_arTabs[index].m_nTabID = getAppWindow().getWebKitEngine()->NewTab();

            if ( m_arTabs[index].m_nTabID < 0 )
            {
                LOG(ERROR) + "New Tab failed with error: " + m_arTabs[index].m_nTabID + "; Tab Index: " + index;

                if ( /*!bCreateOnly &&*/ (m_arTabs[index].m_nTabID == NEWTAB_LOW_MEM || m_arTabs[index].m_nTabID == NEWTAB_MAX_TABS) )
                {
                    LOG(INFO) + "Try to close perishable tab.";
                    removePerishableTab();
                    m_arTabs[index].m_nTabID = getAppWindow().getWebKitEngine()->NewTab();

                    if ( m_arTabs[index].m_nTabID < 0 )
                    {
                        LOG(ERROR) + "New Tab failed with error: " + m_arTabs[index].m_nTabID + "; Tab Index: " + index;
                        raiseTabEvent( "onTabNewError", m_nCurrentTab, index );
                        return;
                    }
                }
            }
            else
                m_arTabs[index].m_hwndTab = getAppWindow().getWebKitEngine()->GetHTMLWND(m_arTabs[index].m_nTabID);

            //raiseTabEvent( "onTabNew", m_nCurrentTab, index );
        }
    }

    if ( !m_arTabs[index].m_hwndTab )
    {
        LOG(ERROR) + "Unable to create Tab. Cannot get Tab Window.";
        return;
    }

    if ( m_nCurrentTab != index && !bCreateOnly)
    {
		if(m_nCurrentTab != -1)
			m_arTabs[m_nCurrentTab].m_strTitle = RHOCONF().getString("title_text");

		getAppWindow().getWebKitEngine()->SwitchTab(m_arTabs[index].m_nTabID);
        int nOldTab = m_nCurrentTab;
        m_nCurrentTab = index;

        if (bNewTab || bByName)
            Sleep(200);

        if(m_nCurrentTab != -1)
		{
			RHOCONF().setString("title_text", m_arTabs[index].m_strTitle.c_str(), false);
			PostMessage(getAppWindow().m_hWnd, WM_COMMAND, ID_TITLECHANGE, 0);
		}

		raiseTabEvent( "onTabFocus", nOldTab, m_nCurrentTab );
    }

    if (  m_arTabs[index].m_strAction.length() > 0 && (m_arTabs[index].m_bReloadPage || bNewTab) )
    {
        LOG(INFO) + "loadUrl";
        RHODESAPP().loadUrl( m_arTabs[index].m_strAction, index );
    }

}

void CNativeTabbar::SetBadge(int index, const char* badge)
{
    //Not implemented
}

int CNativeTabbar::GetCurrentTabID()
{
    if (m_arTabs.size()>0 && m_nCurrentTab < (int)m_arTabs.size() && m_nCurrentTab >= 0 )
	    return m_arTabs[m_nCurrentTab].m_nTabID;

    return 0;
}

int CNativeTabbar::GetTabID(int nIndex)
{
    if ( nIndex < 0 )
        nIndex = m_nCurrentTab;

    if (m_arTabs.size()>0 && nIndex < (int)m_arTabs.size() && nIndex >= 0 )
	    return m_arTabs[nIndex].m_nTabID;

    return 0;
}

int CNativeTabbar::GetCurrentTabIndex()
{
    if (m_arTabs.size()>0 && m_nCurrentTab < (int)m_arTabs.size() && m_nCurrentTab >= 0 )
	    return m_nCurrentTab;

    return 0;
}

bool CNativeTabbar::IsTabBarStarted()
{
    return m_bTabCreated;
}
<commit_msg>EMBPD00151744 : [Rho][Common API]Rho.Application.title set is not visible <commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "stdafx.h"

#include "NativeTabbar.h"
#include "MainWindow.h"
#include "rubyext/WebView.h"
#include "json/JSONIterator.h"

IMPLEMENT_LOGCLASS(CNativeTabbar,"NativeTabbar");

extern CMainWindow& getAppWindow();

using namespace rho::json;

CNativeTabbar::CNativeTabbar()
{
    m_nCurrentTab = -1;
    m_bTabCreated = false;
}

static int getColorFromString(const char* szColor)
{
    if ( !szColor || !*szColor )
        return RGB(0, 0, 0);

	int c = atoi(szColor);

	int cR = (c & 0xFF0000) >> 16;
	int cG = (c & 0xFF00) >> 8;
	int cB = (c & 0xFF);

    return RGB(cR, cG, cB);
}

void CNativeTabbar::CreateTabbarEx(const rho::Vector<rho::String>& tabbarElements, const rho::Hashtable<rho::String, rho::String>& tabBarProperties, rho::apiGenerator::CMethodResult& oResult)
{
    if (!rho_rhodesapp_check_mode() )
        return;

    RemoveTabbar();

	COLORREF   rgbBackColor;
    bool bHiddenTabs = false, bCreateOnInit = false;

    for ( Hashtable<rho::String, rho::String>::const_iterator it = tabBarProperties.begin(); it != tabBarProperties.end(); ++it )
    {
        const char *name = (it->first).c_str();
        const char *value = (it->second).c_str();
        if (strcasecmp(name, "backgroundColor") == 0)
            rgbBackColor = getColorFromString(value);
        if (strcasecmp(name, "hiddenTabs") == 0)
            bHiddenTabs = strcasecmp(value, "true") == 0;
        if (strcasecmp(name, "createOnInit") == 0)
            bCreateOnInit = strcasecmp(value, "true") == 0;

    }

    if ( !bHiddenTabs )
    {
        LOG(WARNING) + "Illegal argument for create_nativebar: hiddenTabs should be true for Windows Mobile and Windows CE.";
        bHiddenTabs = true;
    }

    int nStartTab = -1;

    for (int i = 0; i < (int)tabbarElements.size(); ++i)
    {
        const char *label = NULL;
        const char *action = NULL;
        const char *icon = NULL;
        const char *reload = NULL;
        const char *colored_icon = NULL;

    	COLORREF selected_color;
        const char *disabled = NULL;
		COLORREF web_bkg_color;
        const char* use_current_view_for_tab = NULL;
        bool bUseCurrentViewForTab = false, bReloadPage = false, bPerishable = false, bCreateOnInitTab = false;
        CJSONEntry oEntry(tabbarElements[i].c_str());

        if ( oEntry.hasName("label") )
            label = oEntry.getString("label");
        if ( oEntry.hasName("action") )
            action = oEntry.getString("action");
        if ( oEntry.hasName("icon") )
            icon = oEntry.getString("icon");
        if ( oEntry.hasName("coloredIcon") )
            colored_icon = oEntry.getString("coloredIcon");
        if ( oEntry.hasName("reload") )
        {
            reload = oEntry.getString("reload");
            if (strcasecmp(reload, "true") == 0)
                bReloadPage = true;
        }
        if ( oEntry.hasName("perishable") )
        {
            const char* perishable = oEntry.getString("perishable");
            if (strcasecmp(perishable, "true") == 0)
                bPerishable = true;
        }
        if ( oEntry.hasName("createOnInit") )
        {
            const char* createOnInit = oEntry.getString("createOnInit");
            if (strcasecmp(createOnInit, "true") == 0)
                bCreateOnInitTab = true;
        }

        if ( oEntry.hasName("selectedColor") )
            selected_color = getColorFromString(oEntry.getString("selectedColor"));
        if ( oEntry.hasName("disabled") )
            disabled = oEntry.getString("disabled");
        if ( oEntry.hasName("useCurrentViewForTab") )
        {
            use_current_view_for_tab = oEntry.getString("useCurrentViewForTab");
            if (strcasecmp(use_current_view_for_tab, "true") == 0)
                bUseCurrentViewForTab = true;
        }
        if (oEntry.hasName("backgroundColor"))
            web_bkg_color = getColorFromString(oEntry.getString("backgroundColor"));

        if (label == NULL)
            label = "";
        if (action == NULL)
            action = "";

        m_arTabs.addElement(CTabBarItem(action, label, bUseCurrentViewForTab, bReloadPage, bPerishable, bCreateOnInitTab));

        if (m_strStartTabName.length()>0 && m_strStartTabName == label)
            nStartTab = i;

    }

    if ( oResult.hasCallback() )
        m_oCallback = oResult;

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_bCreateOnInit || bCreateOnInit )
            SwitchTab(i, true);
    }

    if (m_strStartTabName.length()>0&&nStartTab>=0)
    {
        //getAppWindow().SetTimer( TABBAR_TIMER_ID, 1000 );
        SwitchTabByName( m_strStartTabName.c_str(), false );
        m_strStartTabName = "";
    }else if ( m_arTabs.size() ) //&& !m_arTabs[0].m_bUseCurrentViewForTab )
        SwitchTab(0);

    m_bTabCreated = true;
}

LRESULT CNativeTabbar::OnTimer (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SwitchTabByName( m_strStartTabName.c_str(), false );
    m_strStartTabName = "";
    getAppWindow().KillTimer( TABBAR_TIMER_ID );

    return 0;
}

void CNativeTabbar::RemoveTabbar()
{
    getAppWindow().getWebKitEngine()->SwitchTab(0); //Switch to main view

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if (m_arTabs[i].m_nTabID > 0 ) //do not remove tab 0
            getAppWindow().getWebKitEngine()->CloseTab(m_arTabs[i].m_nTabID);
    }

    m_arTabs.removeAllElements();
    m_bTabCreated = false;
    m_nCurrentTab = -1;
}

void CNativeTabbar::RemoveTab(int index)
{
    if (index >= 0 && index < (int)m_arTabs.size() )
    {
        if (m_arTabs[index].m_nTabID > 0 ) //do not remove tab 0
        {
            LOG(INFO) + "Close Tab: " + index;
            getAppWindow().getWebKitEngine()->CloseTab(m_arTabs[index].m_nTabID);

            m_arTabs[index].m_nTabID = -1;
            m_arTabs[index].m_hwndTab = 0;
        }
    }
}

void CNativeTabbar::SwitchTabByName(const char* szTabName, bool bExecuteJS)
{
    LOG(INFO) + "tabbarSwitchByName: " + szTabName;

    if ( !szTabName || !*szTabName)
        return;

    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_strLabel == szTabName )
        {
            /*if ( bExecuteJS )
            {
                String strJS = "Rho.NativeTabbar.switchTab(";
                strJS += convertToStringA(i);
                strJS += ");";

                rho_webview_execute_js( strJS.c_str(), GetCurrentTabIndex() );
            }
            else*/
                SwitchTab(i, false, true);
            break;
        }
    }
}

void CNativeTabbar::raiseTabEvent( const char* szEventName, int nOldTab, int nNewTab )
{
    if ( m_oCallback.hasCallback() )
    {
        LOG(INFO) + "raiseTabEvent: " + szEventName + "; " + nOldTab + "; " + nNewTab;

        Hashtable<String,String> mapRes;
        mapRes["tab_index"] = convertToStringA(nNewTab);
        mapRes["newTabIndex"] = convertToStringA(nNewTab);
        mapRes["oldTabIndex"] = convertToStringA(nOldTab);
        mapRes["tabEvent"] = szEventName;
        m_oCallback.set(mapRes);
    }
}

//as Newtab is a blocking function we have a timeout.
#define NEWTAB_IPC_ERR	-1
#define NEWTAB_TIMEOUT	-2	// the new tab call timed out
#define NEWTAB_LOW_MEM	-3 // A tab cannot be created due to hitting the memory limit m_iMemLimit
#define NEWTAB_MAX_TABS -4 // we have hit the #defined max tabs value defined in Engine2Core; MAX_TABS

bool CNativeTabbar::removePerishableTab()
{
    int nTabToClose = -1;
    for ( int i = 0; i < (int)m_arTabs.size(); i++ )
    {
        if ( m_arTabs[i].m_nTabID > 0 && m_arTabs[i].m_bPerishable && i != m_nCurrentTab )
        {
            nTabToClose = i;
            break;
        }
    }

    if ( nTabToClose == -1 && m_nCurrentTab > 0 )
        nTabToClose = m_nCurrentTab;

    if ( nTabToClose == -1 )
        return false;

    RemoveTab(nTabToClose);
    return true;
}

void CNativeTabbar::SwitchTab(int index, bool bCreateOnly/*=false*/, bool bByName /*= false*/)
{
    if (!getAppWindow().getWebKitEngine())
        return;

    if (( index >= (int)m_arTabs.size() )||(index<0))
    {
        LOG(ERROR) + "Invalid Tab Index: " + index;
        return;
    }

    bool bNewTab = !m_arTabs[index].m_hwndTab;
    if ( !m_arTabs[index].m_hwndTab )
    {
        if ( m_arTabs[index].m_bUseCurrentViewForTab)
        {
            m_arTabs[index].m_nTabID = 0;
            m_arTabs[index].m_hwndTab = getAppWindow().getWebKitEngine()->GetHTMLWND(0);

            bNewTab = false;
        }else
        {
            //raiseTabEvent( "onTabNewRequest", m_nCurrentTab, -1 );

            m_arTabs[index].m_nTabID = getAppWindow().getWebKitEngine()->NewTab();

            if ( m_arTabs[index].m_nTabID < 0 )
            {
                LOG(ERROR) + "New Tab failed with error: " + m_arTabs[index].m_nTabID + "; Tab Index: " + index;

                if ( /*!bCreateOnly &&*/ (m_arTabs[index].m_nTabID == NEWTAB_LOW_MEM || m_arTabs[index].m_nTabID == NEWTAB_MAX_TABS) )
                {
                    LOG(INFO) + "Try to close perishable tab.";
                    removePerishableTab();
                    m_arTabs[index].m_nTabID = getAppWindow().getWebKitEngine()->NewTab();

                    if ( m_arTabs[index].m_nTabID < 0 )
                    {
                        LOG(ERROR) + "New Tab failed with error: " + m_arTabs[index].m_nTabID + "; Tab Index: " + index;
                        raiseTabEvent( "onTabNewError", m_nCurrentTab, index );
                        return;
                    }
                }
            }
            else
                m_arTabs[index].m_hwndTab = getAppWindow().getWebKitEngine()->GetHTMLWND(m_arTabs[index].m_nTabID);

            //raiseTabEvent( "onTabNew", m_nCurrentTab, index );
        }
    }

    if ( !m_arTabs[index].m_hwndTab )
    {
        LOG(ERROR) + "Unable to create Tab. Cannot get Tab Window.";
        return;
    }

    if ( m_nCurrentTab != index && !bCreateOnly)
    {
		if(m_nCurrentTab != -1)
			m_arTabs[m_nCurrentTab].m_strTitle = RHOCONF().getString("title_text");

		getAppWindow().getWebKitEngine()->SwitchTab(m_arTabs[index].m_nTabID);
        int nOldTab = m_nCurrentTab;
        m_nCurrentTab = index;

        if (bNewTab || bByName)
            Sleep(200);

        if(m_nCurrentTab != -1)
		{
			RHOCONF().setString("title_text", ((m_arTabs[index].m_strTitle.length() > 0)?m_arTabs[index].m_strTitle.c_str():RHOCONF().getString("title_text").c_str()), false);
			PostMessage(getAppWindow().m_hWnd, WM_COMMAND, ID_TITLECHANGE, 0);
		}

		raiseTabEvent( "onTabFocus", nOldTab, m_nCurrentTab );
    }

    if (  m_arTabs[index].m_strAction.length() > 0 && (m_arTabs[index].m_bReloadPage || bNewTab) )
    {
        LOG(INFO) + "loadUrl";
        RHODESAPP().loadUrl( m_arTabs[index].m_strAction, index );
    }

}

void CNativeTabbar::SetBadge(int index, const char* badge)
{
    //Not implemented
}

int CNativeTabbar::GetCurrentTabID()
{
    if (m_arTabs.size()>0 && m_nCurrentTab < (int)m_arTabs.size() && m_nCurrentTab >= 0 )
	    return m_arTabs[m_nCurrentTab].m_nTabID;

    return 0;
}

int CNativeTabbar::GetTabID(int nIndex)
{
    if ( nIndex < 0 )
        nIndex = m_nCurrentTab;

    if (m_arTabs.size()>0 && nIndex < (int)m_arTabs.size() && nIndex >= 0 )
	    return m_arTabs[nIndex].m_nTabID;

    return 0;
}

int CNativeTabbar::GetCurrentTabIndex()
{
    if (m_arTabs.size()>0 && m_nCurrentTab < (int)m_arTabs.size() && m_nCurrentTab >= 0 )
	    return m_nCurrentTab;

    return 0;
}

bool CNativeTabbar::IsTabBarStarted()
{
    return m_bTabCreated;
}
<|endoftext|>