<commit_before>// Copyright 2015 Project Vogue. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "elang/lir/emitters/code_buffer.h"

#include "base/logging.h"
#include "elang/api/machine_code_builder.h"
#include "elang/base/zone_allocated.h"
#include "elang/lir/emitters/value_emitter.h"
#include "elang/lir/factory.h"
#include "elang/lir/literals.h"

namespace elang {
namespace lir {

namespace {
// TODO(eval1749) We should move |Is8Bit()| to another place to share code.
bool Is8Bit(int data) {
  return (data & 255) == data;
}
}  // namespace

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::CodeLocation
//
class CodeBuffer::CodeLocation : public ZoneAllocated {
 public:
  CodeLocation(int buffer_offset, int code_offset);
  CodeLocation();

  int buffer_offset() const { return buffer_offset_; }
  int code_offset() const { return code_offset_; }

  void Relocate(int delta);
  void Start(int buffer_offset, int code_offset);

 private:
  int buffer_offset_;
  int code_offset_;

  DISALLOW_COPY_AND_ASSIGN(CodeLocation);
};

CodeBuffer::CodeLocation::CodeLocation(int buffer_offset, int code_offset)
    : buffer_offset_(buffer_offset), code_offset_(code_offset) {
}

CodeBuffer::CodeLocation::CodeLocation()
    : buffer_offset_(-1), code_offset_(-1) {
}

// Relocate this |CodeLocation|. |delta| can be negative for code alignment
// adjustment.
void CodeBuffer::CodeLocation::Relocate(int delta) {
  code_offset_ += delta;
}

void CodeBuffer::CodeLocation::Start(int buffer_offset, int code_offset) {
  DCHECK_EQ(buffer_offset_, -1);
  DCHECK_EQ(code_offset_, -1);
  buffer_offset_ = buffer_offset;
  code_offset_ = code_offset;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::BasicBlockData
//
class CodeBuffer::BasicBlockData : public CodeLocation {
 public:
  BasicBlockData();

  int code_length() const { return code_length_; }
  void set_code_length(int new_length);

  void RelocateBlock(int delta);

 private:
  int code_length_;

  DISALLOW_COPY_AND_ASSIGN(BasicBlockData);
};

CodeBuffer::BasicBlockData::BasicBlockData() : code_length_(-1) {
}

void CodeBuffer::BasicBlockData::set_code_length(int new_length) {
  code_length_ = new_length;
}

void CodeBuffer::BasicBlockData::RelocateBlock(int delta) {
  Relocate(delta);
  code_length_ += delta;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::JumpData
//
class CodeBuffer::JumpData final : public CodeLocation {
 public:
  JumpData(int buffer_offset,
           int code_offset,
           const Jump& long_jump,
           const Jump& short_jump,
           BasicBlockData* target_block);

  ~JumpData() = delete;

  bool is_long_jump() const { return is_long_jump_; }
  const Jump& jump() const { return is_long_jump_ ? long_jump_ : short_jump_; }
  int target_code_offset() const;

  bool IsCrossing(int code_offset) const;
  int RelativeOffset() const;
  const Jump& UseLongJump();

 private:
  friend class JumpResolver;

  bool is_long_jump_;
  const Jump long_jump_;
  const Jump short_jump_;
  const BasicBlockData* const target_block_;

  DISALLOW_COPY_AND_ASSIGN(JumpData);
};

CodeBuffer::JumpData::JumpData(int buffer_offset,
                               int code_offset,
                               const Jump& long_jump,
                               const Jump& short_jump,
                               BasicBlockData* target_block)
    : CodeLocation(buffer_offset, code_offset),
      is_long_jump_(false),
      long_jump_(long_jump),
      short_jump_(short_jump),
      target_block_(target_block) {
  DCHECK_NE(long_jump_.opcode, short_jump.opcode);
  DCHECK_GT(long_jump_.size(), short_jump_.size());
}

bool CodeBuffer::JumpData::IsCrossing(int ref_code_offset) const {
  if (code_offset() < ref_code_offset) {
    //    jump target
    //    -- |code_offset| --
    //  target:
    return target_block_->code_offset() >= ref_code_offset;
  }

  // target:
  //    -- |code_offset|
  //    jump target
  return target_block_->code_offset() < ref_code_offset;
}

int CodeBuffer::JumpData::RelativeOffset() const {
  return target_block_->code_offset() - code_offset();
}

const CodeBuffer::Jump& CodeBuffer::JumpData::UseLongJump() {
  DCHECK(!is_long_jump_);
  is_long_jump_ = true;
  return long_jump_;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::JumpResolver
//
class CodeBuffer::JumpResolver final {
 public:
  explicit JumpResolver(CodeBuffer* code_buffer);
  ~JumpResolver() = default;

  void Run();

 private:
  void AnalyzeJump(JumpData* data);
  void SetJump(const JumpData* data);
  void UpdateWorkSet(int code_offset);

  CodeBuffer* const code_buffer_;
  std::unordered_set<JumpData*> work_set_;

  DISALLOW_COPY_AND_ASSIGN(JumpResolver);
};

CodeBuffer::JumpResolver::JumpResolver(CodeBuffer* code_buffer)
    : code_buffer_(code_buffer) {
}

void CodeBuffer::JumpResolver::AnalyzeJump(JumpData* data) {
  if (data->is_long_jump())
    return;
  auto const relative_offset = data->RelativeOffset();
  if (Is8Bit(relative_offset))
    return;
  UpdateWorkSet(data->code_offset());
  auto const short_jump = data->jump();
  auto const long_jump = data->UseLongJump();
  code_buffer_->RelocateAfter(data->code_offset(),
                              long_jump.size() - short_jump.size());
}

void CodeBuffer::JumpResolver::Run() {
  work_set_.insert(code_buffer_->jump_data_list_.begin(),
                   code_buffer_->jump_data_list_.end());
  while (!work_set_.empty()) {
    auto const data = *work_set_.begin();
    AnalyzeJump(data);
    work_set_.erase(data);
  }
}

void CodeBuffer::JumpResolver::UpdateWorkSet(int code_offset) {
  for (auto const data : code_buffer_->jump_data_list_) {
    if (work_set_.count(data))
      continue;
    if (!data->IsCrossing(code_offset))
      continue;
    work_set_.insert(data);
  }
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::ValueInCode represents reference to |Value| in code buffer.
//
class CodeBuffer::ValueInCode : public CodeLocation {
 public:
  ValueInCode(int buffer_offset, int code_offset, Value value);

  Value value() const { return value_; }

 private:
  const Value value_;

  DISALLOW_COPY_AND_ASSIGN(ValueInCode);
};

CodeBuffer::ValueInCode::ValueInCode(int buffer_offset,
                                     int code_offset,
                                     Value value)
    : CodeLocation(buffer_offset, code_offset), value_(value) {
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer
//
// TODO(eval1749) We should provide hint for size of |bytes_| to reduce
// number of re-allocation of internal buffer.
CodeBuffer::CodeBuffer(const Function* function)
    : code_size_(0), current_block_data_(nullptr) {
  for (auto const block : function->basic_blocks()) {
    auto const data = new (zone()) BasicBlockData();
    block_data_list_.push_back(data);
    block_data_map_[block] = data;
  }
}

void CodeBuffer::AssociateValue(Value value) {
  DCHECK(current_block_data_);
  value_in_code_list_.push_back(
      new (zone()) ValueInCode(buffer_size(), code_size_, value));
}

void CodeBuffer::Finish(const Factory* factory,
                        api::MachineCodeBuilder* builder) {
  // TODO(eval1749) Fix code references, e.g. branches, indirect jumps, etc.
  JumpResolver(this).Run();
  for (auto const jump_data : jump_data_list_)
    PatchJump(jump_data);
  builder->PrepareCode(code_size_);
  for (auto const data : block_data_list_) {
    DCHECK_GE(data->buffer_offset(), 0);
    DCHECK_GE(data->code_offset(), 0);
    // TODO(eval1749) Insert target specific NOP instructions for code
    // alignment.
    if (!data->code_length())
      continue;
    DCHECK_GT(data->code_length(), 0);
    builder->EmitCode(bytes_.data() + data->buffer_offset(),
                      data->code_length());
  }
  ValueEmitter value_emitter(factory, builder);
  for (auto const value_in_code : value_in_code_list_)
    value_emitter.Emit(value_in_code->code_offset(), value_in_code->value());
  builder->FinishCode();
}

void CodeBuffer::Emit16(int value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  bytes_.push_back(static_cast<uint8_t>(value >> 8));
  code_size_ += 2;
}

// Emit |value| in little endian, LSB to MSB
void CodeBuffer::Emit32(uint32_t value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  bytes_.push_back(static_cast<uint8_t>(value >> 8));
  bytes_.push_back(static_cast<uint8_t>(value >> 16));
  bytes_.push_back(static_cast<uint8_t>(value >> 24));
  code_size_ += 4;
}

void CodeBuffer::Emit64(uint64_t value) {
  DCHECK(current_block_data_);
  Emit32(static_cast<int32_t>(value));
  Emit32(static_cast<int32_t>(value >> 32));
}

void CodeBuffer::Emit8(int value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  ++code_size_;
}

// Emit jump into code buffer. We assume all jump are short jump but we reserve
// room for long jump. In |Finish()| function, we change short jumps to long
// jumps if needed.
void CodeBuffer::EmitJump(const Jump& long_jump,
                          const Jump& short_jump,
                          BasicBlock* target_block) {
  DCHECK(current_block_data_);
  DCHECK_NE(long_jump.opcode, short_jump.opcode);
  DCHECK_GT(long_jump.size(), short_jump.size());
  jump_data_list_.push_back(
      new (zone()) JumpData(buffer_size(), code_size_, long_jump, short_jump,
                            block_data_map_[target_block]));
  // Reserve buffer for long jump.
  bytes_.resize(buffer_size() + long_jump.size());
  code_size_ += short_jump.size();
}

void CodeBuffer::EndBasicBlock() {
  DCHECK(current_block_data_);
  auto const data = current_block_data_;
  current_block_data_ = nullptr;
  data->set_code_length(code_size_ - data->code_offset());
}

void CodeBuffer::RelocateAfter(int ref_code_offset, int delta) {
  DCHECK_GT(delta, 0);
  for (auto it = jump_data_list_.rbegin(); it != jump_data_list_.rbegin();
       ++it) {
    auto const jump_data = *it;
    if (jump_data->code_offset() < ref_code_offset)
      continue;
    jump_data->Relocate(delta);
  }
  for (auto it = block_data_list_.rbegin(); it != block_data_list_.rend();
       ++it) {
    auto const block_data = *it;
    if (block_data->code_offset() < ref_code_offset)
      break;
    block_data->RelocateBlock(delta);
  }
  for (auto it = value_in_code_list_.rbegin(); it != value_in_code_list_.rend();
       ++it) {
    auto const value_in_code = *it;
    if (value_in_code->code_offset() < ref_code_offset)
      break;
    value_in_code->Relocate(delta);
  }
}

void CodeBuffer::Patch8(int buffer_offset, int value) {
  bytes_[buffer_offset] = static_cast<uint8_t>(value);
}

void CodeBuffer::Patch32(int buffer_offset, int value) {
  bytes_[buffer_offset] = static_cast<uint8_t>(value >> 24);
  bytes_[buffer_offset + 1] = static_cast<uint8_t>(value >> 16);
  bytes_[buffer_offset + 2] = static_cast<uint8_t>(value >> 8);
  bytes_[buffer_offset + 3] = static_cast<uint8_t>(value);
}

void CodeBuffer::PatchJump(const JumpData* jump_data) {
  auto const jump = jump_data->jump();
  auto offset = jump_data->buffer_offset();

  // Set opcode of jump instruction
  auto opcode = jump.opcode;
  for (auto count = jump.opcode_size; count; --count) {
    Patch8(offset, opcode);
    opcode >>= 8;
    ++offset;
  }

  // Set operand of jump instruction
  auto const relative_offset = jump_data->RelativeOffset();
  if (jump.operand_size == 4) {
    Patch32(offset, relative_offset);
    return;
  }
  if (jump.operand_size == 1) {
    DCHECK(Is8Bit(relative_offset));
    Patch8(offset, relative_offset);
    return;
  }
  NOTREACHED() << "Unsupported relative offset size" << jump.operand_size;
}

void CodeBuffer::StartBasicBlock(const BasicBlock* block) {
  DCHECK(!current_block_data_);
  auto const it = block_data_map_.find(block);
  DCHECK(it != block_data_map_.end());
  auto const data = it->second;
  // TODO(eval1749) If one of incoming edge is back edge, we should align
  // code offset of this block in target's code cache alignment, e.g. 16 bytes.
  data->Start(buffer_size(), code_size_);
  current_block_data_ = it->second;
}

}  // namespace lir
}  // namespace elang
<commit_msg>elang/lir/emitter: Tidy up |CodeBuffer|, introduce destructors.<commit_after>// Copyright 2015 Project Vogue. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "elang/lir/emitters/code_buffer.h"

#include "base/logging.h"
#include "elang/api/machine_code_builder.h"
#include "elang/base/zone_allocated.h"
#include "elang/lir/emitters/value_emitter.h"
#include "elang/lir/factory.h"
#include "elang/lir/literals.h"

namespace elang {
namespace lir {

namespace {
// TODO(eval1749) We should move |Is8Bit()| to another place to share code.
bool Is8Bit(int data) {
  return (data & 255) == data;
}
}  // namespace

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::CodeLocation
//
class CodeBuffer::CodeLocation : public ZoneAllocated {
 public:
  CodeLocation(int buffer_offset, int code_offset);
  CodeLocation();
  ~CodeLocation();

  int buffer_offset() const { return buffer_offset_; }
  int code_offset() const { return code_offset_; }

  void Relocate(int delta);
  void Start(int buffer_offset, int code_offset);

 private:
  int buffer_offset_;
  int code_offset_;

  DISALLOW_COPY_AND_ASSIGN(CodeLocation);
};

CodeBuffer::CodeLocation::CodeLocation(int buffer_offset, int code_offset)
    : buffer_offset_(buffer_offset), code_offset_(code_offset) {
}

CodeBuffer::CodeLocation::CodeLocation()
    : buffer_offset_(-1), code_offset_(-1) {
}

CodeBuffer::CodeLocation::~CodeLocation() {
  NOTREACHED();
}

// Relocate this |CodeLocation|. |delta| can be negative for code alignment
// adjustment.
void CodeBuffer::CodeLocation::Relocate(int delta) {
  code_offset_ += delta;
}

void CodeBuffer::CodeLocation::Start(int buffer_offset, int code_offset) {
  DCHECK_EQ(buffer_offset_, -1);
  DCHECK_EQ(code_offset_, -1);
  buffer_offset_ = buffer_offset;
  code_offset_ = code_offset;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::BasicBlockData
//
class CodeBuffer::BasicBlockData : public CodeLocation {
 public:
  BasicBlockData();
  ~BasicBlockData() = delete;

  int code_length() const { return code_length_; }
  void set_code_length(int new_length);

  void RelocateBlock(int delta);

 private:
  int code_length_;

  DISALLOW_COPY_AND_ASSIGN(BasicBlockData);
};

CodeBuffer::BasicBlockData::BasicBlockData() : code_length_(-1) {
}

void CodeBuffer::BasicBlockData::set_code_length(int new_length) {
  code_length_ = new_length;
}

void CodeBuffer::BasicBlockData::RelocateBlock(int delta) {
  Relocate(delta);
  code_length_ += delta;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::JumpData
//
class CodeBuffer::JumpData final : public CodeLocation {
 public:
  JumpData(int buffer_offset,
           int code_offset,
           const Jump& long_jump,
           const Jump& short_jump,
           BasicBlockData* target_block);

  ~JumpData() = delete;

  bool is_long_jump() const { return is_long_jump_; }
  const Jump& jump() const { return is_long_jump_ ? long_jump_ : short_jump_; }
  int target_code_offset() const;

  bool IsCrossing(int code_offset) const;
  int RelativeOffset() const;
  const Jump& UseLongJump();

 private:
  friend class JumpResolver;

  bool is_long_jump_;
  const Jump long_jump_;
  const Jump short_jump_;
  const BasicBlockData* const target_block_;

  DISALLOW_COPY_AND_ASSIGN(JumpData);
};

CodeBuffer::JumpData::JumpData(int buffer_offset,
                               int code_offset,
                               const Jump& long_jump,
                               const Jump& short_jump,
                               BasicBlockData* target_block)
    : CodeLocation(buffer_offset, code_offset),
      is_long_jump_(false),
      long_jump_(long_jump),
      short_jump_(short_jump),
      target_block_(target_block) {
  DCHECK_NE(long_jump_.opcode, short_jump.opcode);
  DCHECK_GT(long_jump_.size(), short_jump_.size());
}

bool CodeBuffer::JumpData::IsCrossing(int ref_code_offset) const {
  if (code_offset() < ref_code_offset) {
    //    jump target
    //    -- |code_offset| --
    //  target:
    return target_block_->code_offset() >= ref_code_offset;
  }

  // target:
  //    -- |code_offset|
  //    jump target
  return target_block_->code_offset() < ref_code_offset;
}

int CodeBuffer::JumpData::RelativeOffset() const {
  return target_block_->code_offset() - code_offset();
}

const CodeBuffer::Jump& CodeBuffer::JumpData::UseLongJump() {
  DCHECK(!is_long_jump_);
  is_long_jump_ = true;
  return long_jump_;
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::JumpResolver
//
class CodeBuffer::JumpResolver final {
 public:
  explicit JumpResolver(CodeBuffer* code_buffer);
  ~JumpResolver() = default;

  void Run();

 private:
  void AnalyzeJump(JumpData* data);
  void SetJump(const JumpData* data);
  void UpdateWorkSet(int code_offset);

  CodeBuffer* const code_buffer_;
  std::unordered_set<JumpData*> work_set_;

  DISALLOW_COPY_AND_ASSIGN(JumpResolver);
};

CodeBuffer::JumpResolver::JumpResolver(CodeBuffer* code_buffer)
    : code_buffer_(code_buffer) {
}

void CodeBuffer::JumpResolver::AnalyzeJump(JumpData* data) {
  if (data->is_long_jump())
    return;
  auto const relative_offset = data->RelativeOffset();
  if (Is8Bit(relative_offset))
    return;
  UpdateWorkSet(data->code_offset());
  auto const short_jump = data->jump();
  auto const long_jump = data->UseLongJump();
  code_buffer_->RelocateAfter(data->code_offset(),
                              long_jump.size() - short_jump.size());
}

void CodeBuffer::JumpResolver::Run() {
  work_set_.insert(code_buffer_->jump_data_list_.begin(),
                   code_buffer_->jump_data_list_.end());
  while (!work_set_.empty()) {
    auto const data = *work_set_.begin();
    AnalyzeJump(data);
    work_set_.erase(data);
  }
}

void CodeBuffer::JumpResolver::UpdateWorkSet(int code_offset) {
  for (auto const data : code_buffer_->jump_data_list_) {
    if (work_set_.count(data))
      continue;
    if (!data->IsCrossing(code_offset))
      continue;
    work_set_.insert(data);
  }
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer::ValueInCode represents reference to |Value| in code buffer.
//
class CodeBuffer::ValueInCode : public CodeLocation {
 public:
  ValueInCode(int buffer_offset, int code_offset, Value value);
  ~ValueInCode() = delete;

  Value value() const { return value_; }

 private:
  const Value value_;

  DISALLOW_COPY_AND_ASSIGN(ValueInCode);
};

CodeBuffer::ValueInCode::ValueInCode(int buffer_offset,
                                     int code_offset,
                                     Value value)
    : CodeLocation(buffer_offset, code_offset), value_(value) {
}

//////////////////////////////////////////////////////////////////////
//
// CodeBuffer
//
// TODO(eval1749) We should provide hint for size of |bytes_| to reduce
// number of re-allocation of internal buffer.
CodeBuffer::CodeBuffer(const Function* function)
    : code_size_(0), current_block_data_(nullptr) {
  for (auto const block : function->basic_blocks()) {
    auto const data = new (zone()) BasicBlockData();
    block_data_list_.push_back(data);
    block_data_map_[block] = data;
  }
}

void CodeBuffer::AssociateValue(Value value) {
  DCHECK(current_block_data_);
  value_in_code_list_.push_back(
      new (zone()) ValueInCode(buffer_size(), code_size_, value));
}

void CodeBuffer::Finish(const Factory* factory,
                        api::MachineCodeBuilder* builder) {
  // TODO(eval1749) Fix code references, e.g. branches, indirect jumps, etc.
  JumpResolver(this).Run();
  for (auto const jump_data : jump_data_list_)
    PatchJump(jump_data);
  builder->PrepareCode(code_size_);
  for (auto const data : block_data_list_) {
    DCHECK_GE(data->buffer_offset(), 0);
    DCHECK_GE(data->code_offset(), 0);
    // TODO(eval1749) Insert target specific NOP instructions for code
    // alignment.
    if (!data->code_length())
      continue;
    DCHECK_GT(data->code_length(), 0);
    builder->EmitCode(bytes_.data() + data->buffer_offset(),
                      data->code_length());
  }
  ValueEmitter value_emitter(factory, builder);
  for (auto const value_in_code : value_in_code_list_)
    value_emitter.Emit(value_in_code->code_offset(), value_in_code->value());
  builder->FinishCode();
}

void CodeBuffer::Emit16(int value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  bytes_.push_back(static_cast<uint8_t>(value >> 8));
  code_size_ += 2;
}

// Emit |value| in little endian, LSB to MSB
void CodeBuffer::Emit32(uint32_t value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  bytes_.push_back(static_cast<uint8_t>(value >> 8));
  bytes_.push_back(static_cast<uint8_t>(value >> 16));
  bytes_.push_back(static_cast<uint8_t>(value >> 24));
  code_size_ += 4;
}

void CodeBuffer::Emit64(uint64_t value) {
  DCHECK(current_block_data_);
  Emit32(static_cast<int32_t>(value));
  Emit32(static_cast<int32_t>(value >> 32));
}

void CodeBuffer::Emit8(int value) {
  DCHECK(current_block_data_);
  bytes_.push_back(static_cast<uint8_t>(value));
  ++code_size_;
}

// Emit jump into code buffer. We assume all jump are short jump but we reserve
// room for long jump. In |Finish()| function, we change short jumps to long
// jumps if needed.
void CodeBuffer::EmitJump(const Jump& long_jump,
                          const Jump& short_jump,
                          BasicBlock* target_block) {
  DCHECK(current_block_data_);
  DCHECK_NE(long_jump.opcode, short_jump.opcode);
  DCHECK_GT(long_jump.size(), short_jump.size());
  jump_data_list_.push_back(
      new (zone()) JumpData(buffer_size(), code_size_, long_jump, short_jump,
                            block_data_map_[target_block]));
  // Reserve buffer for long jump.
  bytes_.resize(buffer_size() + long_jump.size());
  code_size_ += short_jump.size();
}

void CodeBuffer::EndBasicBlock() {
  DCHECK(current_block_data_);
  auto const data = current_block_data_;
  current_block_data_ = nullptr;
  data->set_code_length(code_size_ - data->code_offset());
}

void CodeBuffer::RelocateAfter(int ref_code_offset, int delta) {
  DCHECK_GT(delta, 0);
  for (auto it = jump_data_list_.rbegin(); it != jump_data_list_.rbegin();
       ++it) {
    auto const jump_data = *it;
    if (jump_data->code_offset() < ref_code_offset)
      continue;
    jump_data->Relocate(delta);
  }
  for (auto it = block_data_list_.rbegin(); it != block_data_list_.rend();
       ++it) {
    auto const block_data = *it;
    if (block_data->code_offset() < ref_code_offset)
      break;
    block_data->RelocateBlock(delta);
  }
  for (auto it = value_in_code_list_.rbegin(); it != value_in_code_list_.rend();
       ++it) {
    auto const value_in_code = *it;
    if (value_in_code->code_offset() < ref_code_offset)
      break;
    value_in_code->Relocate(delta);
  }
}

void CodeBuffer::Patch8(int buffer_offset, int value) {
  bytes_[buffer_offset] = static_cast<uint8_t>(value);
}

void CodeBuffer::Patch32(int buffer_offset, int value) {
  bytes_[buffer_offset] = static_cast<uint8_t>(value >> 24);
  bytes_[buffer_offset + 1] = static_cast<uint8_t>(value >> 16);
  bytes_[buffer_offset + 2] = static_cast<uint8_t>(value >> 8);
  bytes_[buffer_offset + 3] = static_cast<uint8_t>(value);
}

void CodeBuffer::PatchJump(const JumpData* jump_data) {
  auto const jump = jump_data->jump();
  auto offset = jump_data->buffer_offset();

  // Set opcode of jump instruction
  auto opcode = jump.opcode;
  for (auto count = jump.opcode_size; count; --count) {
    Patch8(offset, opcode);
    opcode >>= 8;
    ++offset;
  }

  // Set operand of jump instruction
  auto const relative_offset = jump_data->RelativeOffset();
  if (jump.operand_size == 4) {
    Patch32(offset, relative_offset);
    return;
  }
  if (jump.operand_size == 1) {
    DCHECK(Is8Bit(relative_offset));
    Patch8(offset, relative_offset);
    return;
  }
  NOTREACHED() << "Unsupported relative offset size" << jump.operand_size;
}

void CodeBuffer::StartBasicBlock(const BasicBlock* block) {
  DCHECK(!current_block_data_);
  auto const it = block_data_map_.find(block);
  DCHECK(it != block_data_map_.end());
  auto const data = it->second;
  // TODO(eval1749) If one of incoming edge is back edge, we should align
  // code offset of this block in target's code cache alignment, e.g. 16 bytes.
  data->Start(buffer_size(), code_size_);
  current_block_data_ = it->second;
}

}  // namespace lir
}  // namespace elang
<|endoftext|>


<commit_before>/*
  The MIT License (MIT)

  Copyright (c) 2015 Andrea Scarpino <me@andreascarpino.it>

  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.
*/

#include "hackernewsapi.h"

#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>

#include "item.h"

const static QString API_URL = "https://hacker-news.firebaseio.com/v0/";

HackerNewsAPI::HackerNewsAPI(QObject *parent) :
    QObject(parent)
  , network(new QNetworkAccessManager(this))
{
}

HackerNewsAPI::~HackerNewsAPI()
{
    delete network;
}

void HackerNewsAPI::getItem(const int id)
{
    qDebug() << "Requesting item with id" << id;

    QUrl url(API_URL + QString("item/%1.json").arg(id));
    QNetworkRequest req(url);
    QNetworkReply* reply = network->get(req);

    connect(reply, SIGNAL(finished()), this, SLOT(onGetItemResult()));
}

void HackerNewsAPI::getStories(Stories kind)
{
    qDebug() << "Requesting new stories";

    QString path;
    switch (kind) {
    case Ask: path = QString("askstories.json"); break;
    case Job: path = QString("jobstories.json"); break;
    case New: path = QString("newstories.json"); break;
    case Show: path = QString("showstories.json"); break;
    case Top: path = QString("topstories.json");
    }

    QUrl url(API_URL + path);
    QNetworkRequest req(url);
    QNetworkReply* reply = network->get(req);

    connect(reply, SIGNAL(finished()), this, SLOT(onStoriesResult()));
}

void HackerNewsAPI::onGetItemResult()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    if (!reply || reply->error() != QNetworkReply::NoError) {
        qCritical() << "Cannot fetch item";
        return;
    }

    QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
    if (!json.isNull()) {
        qDebug() << "Got item:\n" << json;

        Item* item = new Item();
        QJsonObject jsonObj = json.object();
        item->setId(jsonObj.value("id").toInt());
        item->setBy(jsonObj.value("by").toString());
        item->setDeleted(jsonObj.value("deleted").toBool());
        item->setDescendants(jsonObj.value("descendants").toInt());

        QJsonArray jsonKids = jsonObj.value("kids").toArray();
        QList<int> kids;
        Q_FOREACH (const QVariant kid, jsonKids.toVariantList()) {
            kids.append(kid.toInt());
        }
        item->setKids(kids);

        item->setText(jsonObj.value("text").toString());
        item->setTitle(jsonObj.value("title").toString());
        item->setUrl(QUrl(jsonObj.value("url").toString()));

        // FIXME: to be removed when we display items text and comments
        // Since we don't display hacker news items yet, we just set
        // the external url to the item detail page in Hacker News
        if (item->url().isEmpty()) {
            item->setUrl(QUrl("https://news.ycombinator.com/item?id=" + QString::number(item->id())));
        }

        item->setScore(jsonObj.value("score").toInt());
        QDateTime timestamp;
        timestamp.setTime_t(jsonObj.value("time").toInt());
        item->setTime(timestamp);

        emit itemFetched(item);
    }

    reply->deleteLater();
}

void HackerNewsAPI::onStoriesResult()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    if (!reply || reply->error() != QNetworkReply::NoError) {
        qCritical() << "Cannot fetch stories";
        return;
    }

    QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
    if (!json.isNull()) {
        qDebug() << "Got" << json.array().size() << "items";

        QList<int> ids;
        Q_FOREACH (const QJsonValue id, json.array()) {
            ids.append(id.toInt());
        }

        emit storiesFetched(ids);
    }

    reply->deleteLater();
}
<commit_msg>Fix possible memleak on reply->error()<commit_after>/*
  The MIT License (MIT)

  Copyright (c) 2015 Andrea Scarpino <me@andreascarpino.it>

  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.
*/

#include "hackernewsapi.h"

#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>

#include "item.h"

const static QString API_URL = QStringLiteral("https://hacker-news.firebaseio.com/v0/");

HackerNewsAPI::HackerNewsAPI(QObject *parent) :
    QObject(parent)
  , network(new QNetworkAccessManager(this))
{
}

HackerNewsAPI::~HackerNewsAPI()
{
    delete network;
}

void HackerNewsAPI::getItem(const int id)
{
    qDebug() << "Requesting item with id" << id;

    QUrl url(API_URL + QString("item/%1.json").arg(id));
    QNetworkRequest req(url);
    QNetworkReply* reply = network->get(req);

    connect(reply, SIGNAL(finished()), this, SLOT(onGetItemResult()));
}

void HackerNewsAPI::getStories(Stories kind)
{
    qDebug() << "Requesting new stories";

    QString path;
    switch (kind) {
        case Ask: path = QString("askstories.json"); break;
        case Job: path = QString("jobstories.json"); break;
        case New: path = QString("newstories.json"); break;
        case Show: path = QString("showstories.json"); break;
        case Top: path = QString("topstories.json");
    }

    QUrl url(API_URL + path);
    QNetworkRequest req(url);
    QNetworkReply* reply = network->get(req);

    connect(reply, SIGNAL(finished()), this, SLOT(onStoriesResult()));
}

void HackerNewsAPI::onGetItemResult()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    if (reply->error() != QNetworkReply::NoError) {
        qCritical() << "Cannot fetch item";
    } else {
        QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
        if (!json.isNull()) {
            //qDebug() << "Got item:\n" << json;

            Item* item = new Item();
            QJsonObject jsonObj = json.object();
            item->setId(jsonObj.value("id").toInt());
            item->setBy(jsonObj.value("by").toString());
            item->setDeleted(jsonObj.value("deleted").toBool());
            item->setDescendants(jsonObj.value("descendants").toInt());

            QJsonArray jsonKids = jsonObj.value("kids").toArray();
            QList<int> kids;
            Q_FOREACH (const QVariant kid, jsonKids.toVariantList()) {
                kids.append(kid.toInt());
            }
            item->setKids(kids);

            item->setText(jsonObj.value("text").toString());
            item->setTitle(jsonObj.value("title").toString());
            item->setUrl(QUrl(jsonObj.value("url").toString()));

            // FIXME: to be removed when we display items text and comments
            // Since we don't display hacker news items yet, we just set
            // the external url to the item detail page in Hacker News
            if (item->url().isEmpty()) {
                item->setUrl(QUrl("https://news.ycombinator.com/item?id=" + QString::number(item->id())));
            }

            item->setScore(jsonObj.value("score").toInt());
            QDateTime timestamp;
            timestamp.setTime_t(jsonObj.value("time").toInt());
            item->setTime(timestamp);

            emit itemFetched(item);
        }
    }

    reply->deleteLater();
}

void HackerNewsAPI::onStoriesResult()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());

    if (reply->error() != QNetworkReply::NoError) {
        qCritical() << "Cannot fetch stories";
    } else {
        QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
        if (!json.isNull()) {
            qDebug() << "Got" << json.array().size() << "items";

            QList<int> ids;
            Q_FOREACH (const QJsonValue id, json.array()) {
                ids.append(id.toInt());
            }

            emit storiesFetched(ids);
        }
    }

    reply->deleteLater();
}
<|endoftext|>


<commit_before>#include <Python.h>
#include "numpy/arrayobject.h"

#include <cmath>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <new>
#include <typeinfo>
#include <stdexcept>
#include <ios>

#define CKDTREE_METHODS_IMPL
#include "ckdtree_decl.h"
#include "ckdtree_methods.h"
#include "cpp_exc.h"
#include "rectangle.h"

struct WeightedTree {
    const ckdtree *tree;
    npy_float64 *weights;
    npy_float64 *node_weights;
};
struct CNBParams
{
    npy_float64 *r;
    void * results; /* will be casted inside */
    WeightedTree self, other;
};

template <typename MinMaxDist, typename WeightType, typename ResultType> static void
traverse(
    RectRectDistanceTracker<MinMaxDist> *tracker,
    const CNBParams *params,
    npy_float64 *start, npy_float64 *end,
    const ckdtreenode *node1,
    const ckdtreenode *node2)
{
    static void (* const next)(RectRectDistanceTracker<MinMaxDist> *tracker,
            const CNBParams *params,
            npy_float64 *start, npy_float64 *end,
            const ckdtreenode *node1,
            const ckdtreenode *node2) = traverse<MinMaxDist, WeightType, ResultType>;

    ResultType *results = (ResultType*) params->results;

    /*
     * Speed through pairs of nodes all of whose children are close
     * and see if any work remains to be done
     */

    start = std::lower_bound(start, end, tracker->min_distance);
    end = std::lower_bound(start, end, tracker->max_distance);

    /* since max_distance >= min_distance, end < start never happens */
    if (end == start) {
        results[start - params->r] += WeightType::get_weight(&params->self, node1)
                                    * WeightType::get_weight(&params->other, node2);
        return;
    }

    /* OK, need to probe a bit deeper */
    if (node1->split_dim == -1) {  /* 1 is leaf node */
        if (node2->split_dim == -1) {  /* 1 & 2 are leaves */
            npy_intp i, j;
            const npy_float64 p = tracker->p;
            const npy_float64 tmd = tracker->max_distance;
            const npy_float64 *sdata = params->self.tree->raw_data;
            const npy_intp *sindices = params->self.tree->raw_indices;
            const npy_float64 *odata = params->other.tree->raw_data;
            const npy_intp *oindices = params->other.tree->raw_indices;
            const npy_intp m = params->self.tree->m;
            const npy_intp start1 = node1->start_idx;
            const npy_intp start2 = node2->start_idx;
            const npy_intp end1 = node1->end_idx;
            const npy_intp end2 = node2->end_idx;

            prefetch_datapoint(sdata + sindices[start1] * m, m);

            if (start1 < end1)
                prefetch_datapoint(sdata + sindices[start1+1] * m, m);

            /* brute-force */
            for (i = start1; i < end1; ++i) {

                if (i < end1-2)
                    prefetch_datapoint(sdata + sindices[i+2] * m, m);

                prefetch_datapoint(odata + oindices[start2] * m, m);

                if (start2 < end2)
                    prefetch_datapoint(odata + oindices[start2+1] * m, m);

                for (j = start2; j < end2; ++j) {

                    if (j < end2-2)
                        prefetch_datapoint(odata + oindices[j+2] * m, m);

                    npy_float64 d = MinMaxDist::distance_p(params->self.tree,
                            sdata + sindices[i] * m,
                            odata + oindices[j] * m,
                            p, m, tmd);

                    const npy_float64 *l = std::lower_bound(start, end, d);
                    results[l - params->r] += WeightType::get_weight(&params->self, sindices[i])
                                            * WeightType::get_weight(&params->other, sindices[j]);
                }
            }
        }
        else {  /* 1 is a leaf node, 2 is inner node */
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1, node2->greater);
            tracker->pop();
        }
    }
    else { /* 1 is an inner node */
        if (node2->split_dim == -1) {
            /* 1 is an inner node, 2 is a leaf node */
            tracker->push_less_of(1, node1);
            next(tracker, params, start, end, node1->less, node2);
            tracker->pop();

            tracker->push_greater_of(1, node1);
            next(tracker, params, start, end, node1->greater, node2);
            tracker->pop();
        }
        else { /* 1 and 2 are inner nodes */
            tracker->push_less_of(1, node1);
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1->less, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1->less, node2->greater);
            tracker->pop();
            tracker->pop();

            tracker->push_greater_of(1, node1);
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1->greater, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1->greater, node2->greater);
            tracker->pop();
            tracker->pop();
        }
    }
}

template <typename WeightType, typename ResultType> void
count_neighbors(struct CNBParams *params,
                npy_intp n_queries, const npy_float64 p)
{

    const ckdtree *self = params->self.tree;
    const ckdtree *other = params->other.tree;

#define HANDLE(cond, kls) \
    if (cond) { \
        RectRectDistanceTracker<kls> tracker(self, r1, r2, p, 0.0, 0.0);\
        traverse<kls, WeightType, ResultType>(&tracker, params, params->r, params->r+n_queries, \
                 self->ctree, other->ctree); \
    } else

    Rectangle r1(self->m, self->raw_mins, self->raw_maxes);
    Rectangle r2(other->m, other->raw_mins, other->raw_maxes);

    if (NPY_LIKELY(self->raw_boxsize_data == NULL)) {
        HANDLE(NPY_LIKELY(p == 2), MinkowskiDistP2)
        HANDLE(p == 1, MinkowskiDistP1)
        HANDLE(ckdtree_isinf(p), MinkowskiDistPinf)
        HANDLE(1, MinkowskiDistPp)
        {}
    } else {
        HANDLE(NPY_LIKELY(p == 2), BoxMinkowskiDistP2)
        HANDLE(p == 1, BoxMinkowskiDistP1)
        HANDLE(ckdtree_isinf(p), BoxMinkowskiDistPinf)
        HANDLE(1, BoxMinkowskiDistPp)
        {}
    }
}

struct Unweighted {
    /* the interface for accessing weights of unweighted data. */
    static inline npy_intp
    get_weight(const WeightedTree *wt, const ckdtreenode * node)
    {
        return node->children;
    }
    static inline npy_intp
    get_weight(const WeightedTree *wt, const npy_intp i)
    {
        return 1;
    }
};

extern "C" PyObject*
count_neighbors_unweighted(const ckdtree *self, const ckdtree *other,
                npy_intp n_queries, npy_float64 *real_r, npy_intp *results,
                const npy_float64 p) {

    CNBParams params = {0};

    params.r = real_r;
    params.results = (void*) results;
    params.self.tree = self;
    params.other.tree = other;

    /* release the GIL */
    NPY_BEGIN_ALLOW_THREADS
    {
        try {
            count_neighbors<Unweighted, npy_intp>(&params, n_queries, p);
        }
        catch(...) {
            translate_cpp_exception_with_gil();
        }
    }
    /* reacquire the GIL */
    NPY_END_ALLOW_THREADS

    if (PyErr_Occurred())
        /* true if a C++ exception was translated */
        return NULL;
    else {
        /* return None if there were no errors */
        Py_RETURN_NONE;
    }
}

struct Weighted {
    /* the interface for accessing weights of weighted data. */
    static inline npy_float64
    get_weight(const WeightedTree *wt, const ckdtreenode * node)
    {
        return (wt->weights != NULL)
           ? wt->node_weights[node - wt->tree->ctree]
           : node->children;
    }
    static inline npy_float64
    get_weight(const WeightedTree *wt, const npy_intp i)
    {
        return (wt->weights != NULL)?wt->weights[i]:1;
    }
};

extern "C" PyObject*
count_neighbors_weighted(const ckdtree *self, const ckdtree *other,
                npy_float64 *self_weights, npy_float64 *other_weights,
                npy_float64 *self_node_weights, npy_float64 *other_node_weights,
                npy_intp n_queries, npy_float64 *real_r, npy_float64 *results,
                const npy_float64 p)
{

    CNBParams params = {0};

    params.r = real_r;
    params.results = (void*) results;

    if (self_weights) {
        params.self.tree = self;
        params.self.weights = self_weights;
        params.self.node_weights = self_node_weights;
    }
    if (other_weights) {
        params.other.tree = other;
        params.other.weights = other_weights;
        params.other.node_weights = other_node_weights;
    }
    /* release the GIL */
    NPY_BEGIN_ALLOW_THREADS
    {
        try {
            count_neighbors<Weighted, npy_float64>(&params, n_queries, p);
        }
        catch(...) {
            translate_cpp_exception_with_gil();
        }
    }
    /* reacquire the GIL */
    NPY_END_ALLOW_THREADS

    if (PyErr_Occurred())
        /* true if a C++ exception was translated */
        return NULL;
    else {
        /* return None if there were no errors */
        Py_RETURN_NONE;
    }
}

<commit_msg>BUG: Fix core dump when self_weight or other_weight is None.<commit_after>#include <Python.h>
#include "numpy/arrayobject.h"

#include <cmath>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <new>
#include <typeinfo>
#include <stdexcept>
#include <ios>

#define CKDTREE_METHODS_IMPL
#include "ckdtree_decl.h"
#include "ckdtree_methods.h"
#include "cpp_exc.h"
#include "rectangle.h"

struct WeightedTree {
    const ckdtree *tree;
    npy_float64 *weights;
    npy_float64 *node_weights;
};
struct CNBParams
{
    npy_float64 *r;
    void * results; /* will be casted inside */
    WeightedTree self, other;
};

template <typename MinMaxDist, typename WeightType, typename ResultType> static void
traverse(
    RectRectDistanceTracker<MinMaxDist> *tracker,
    const CNBParams *params,
    npy_float64 *start, npy_float64 *end,
    const ckdtreenode *node1,
    const ckdtreenode *node2)
{
    static void (* const next)(RectRectDistanceTracker<MinMaxDist> *tracker,
            const CNBParams *params,
            npy_float64 *start, npy_float64 *end,
            const ckdtreenode *node1,
            const ckdtreenode *node2) = traverse<MinMaxDist, WeightType, ResultType>;

    ResultType *results = (ResultType*) params->results;

    /*
     * Speed through pairs of nodes all of whose children are close
     * and see if any work remains to be done
     */

    start = std::lower_bound(start, end, tracker->min_distance);
    end = std::lower_bound(start, end, tracker->max_distance);

    /* since max_distance >= min_distance, end < start never happens */
    if (end == start) {
        results[start - params->r] += WeightType::get_weight(&params->self, node1)
                                    * WeightType::get_weight(&params->other, node2);
        return;
    }

    /* OK, need to probe a bit deeper */
    if (node1->split_dim == -1) {  /* 1 is leaf node */
        if (node2->split_dim == -1) {  /* 1 & 2 are leaves */
            npy_intp i, j;
            const npy_float64 p = tracker->p;
            const npy_float64 tmd = tracker->max_distance;
            const npy_float64 *sdata = params->self.tree->raw_data;
            const npy_intp *sindices = params->self.tree->raw_indices;
            const npy_float64 *odata = params->other.tree->raw_data;
            const npy_intp *oindices = params->other.tree->raw_indices;
            const npy_intp m = params->self.tree->m;
            const npy_intp start1 = node1->start_idx;
            const npy_intp start2 = node2->start_idx;
            const npy_intp end1 = node1->end_idx;
            const npy_intp end2 = node2->end_idx;

            prefetch_datapoint(sdata + sindices[start1] * m, m);

            if (start1 < end1)
                prefetch_datapoint(sdata + sindices[start1+1] * m, m);

            /* brute-force */
            for (i = start1; i < end1; ++i) {

                if (i < end1-2)
                    prefetch_datapoint(sdata + sindices[i+2] * m, m);

                prefetch_datapoint(odata + oindices[start2] * m, m);

                if (start2 < end2)
                    prefetch_datapoint(odata + oindices[start2+1] * m, m);

                for (j = start2; j < end2; ++j) {

                    if (j < end2-2)
                        prefetch_datapoint(odata + oindices[j+2] * m, m);

                    npy_float64 d = MinMaxDist::distance_p(params->self.tree,
                            sdata + sindices[i] * m,
                            odata + oindices[j] * m,
                            p, m, tmd);

                    const npy_float64 *l = std::lower_bound(start, end, d);
                    results[l - params->r] += WeightType::get_weight(&params->self, sindices[i])
                                            * WeightType::get_weight(&params->other, sindices[j]);
                }
            }
        }
        else {  /* 1 is a leaf node, 2 is inner node */
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1, node2->greater);
            tracker->pop();
        }
    }
    else { /* 1 is an inner node */
        if (node2->split_dim == -1) {
            /* 1 is an inner node, 2 is a leaf node */
            tracker->push_less_of(1, node1);
            next(tracker, params, start, end, node1->less, node2);
            tracker->pop();

            tracker->push_greater_of(1, node1);
            next(tracker, params, start, end, node1->greater, node2);
            tracker->pop();
        }
        else { /* 1 and 2 are inner nodes */
            tracker->push_less_of(1, node1);
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1->less, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1->less, node2->greater);
            tracker->pop();
            tracker->pop();

            tracker->push_greater_of(1, node1);
            tracker->push_less_of(2, node2);
            next(tracker, params, start, end, node1->greater, node2->less);
            tracker->pop();

            tracker->push_greater_of(2, node2);
            next(tracker, params, start, end, node1->greater, node2->greater);
            tracker->pop();
            tracker->pop();
        }
    }
}

template <typename WeightType, typename ResultType> void
count_neighbors(struct CNBParams *params,
                npy_intp n_queries, const npy_float64 p)
{

    const ckdtree *self = params->self.tree;
    const ckdtree *other = params->other.tree;

#define HANDLE(cond, kls) \
    if (cond) { \
        RectRectDistanceTracker<kls> tracker(self, r1, r2, p, 0.0, 0.0);\
        traverse<kls, WeightType, ResultType>(&tracker, params, params->r, params->r+n_queries, \
                 self->ctree, other->ctree); \
    } else

    Rectangle r1(self->m, self->raw_mins, self->raw_maxes);
    Rectangle r2(other->m, other->raw_mins, other->raw_maxes);

    if (NPY_LIKELY(self->raw_boxsize_data == NULL)) {
        HANDLE(NPY_LIKELY(p == 2), MinkowskiDistP2)
        HANDLE(p == 1, MinkowskiDistP1)
        HANDLE(ckdtree_isinf(p), MinkowskiDistPinf)
        HANDLE(1, MinkowskiDistPp)
        {}
    } else {
        HANDLE(NPY_LIKELY(p == 2), BoxMinkowskiDistP2)
        HANDLE(p == 1, BoxMinkowskiDistP1)
        HANDLE(ckdtree_isinf(p), BoxMinkowskiDistPinf)
        HANDLE(1, BoxMinkowskiDistPp)
        {}
    }
}

struct Unweighted {
    /* the interface for accessing weights of unweighted data. */
    static inline npy_intp
    get_weight(const WeightedTree *wt, const ckdtreenode * node)
    {
        return node->children;
    }
    static inline npy_intp
    get_weight(const WeightedTree *wt, const npy_intp i)
    {
        return 1;
    }
};

extern "C" PyObject*
count_neighbors_unweighted(const ckdtree *self, const ckdtree *other,
                npy_intp n_queries, npy_float64 *real_r, npy_intp *results,
                const npy_float64 p) {

    CNBParams params = {0};

    params.r = real_r;
    params.results = (void*) results;
    params.self.tree = self;
    params.other.tree = other;

    /* release the GIL */
    NPY_BEGIN_ALLOW_THREADS
    {
        try {
            count_neighbors<Unweighted, npy_intp>(&params, n_queries, p);
        }
        catch(...) {
            translate_cpp_exception_with_gil();
        }
    }
    /* reacquire the GIL */
    NPY_END_ALLOW_THREADS

    if (PyErr_Occurred())
        /* true if a C++ exception was translated */
        return NULL;
    else {
        /* return None if there were no errors */
        Py_RETURN_NONE;
    }
}

struct Weighted {
    /* the interface for accessing weights of weighted data. */
    static inline npy_float64
    get_weight(const WeightedTree *wt, const ckdtreenode * node)
    {
        return (wt->weights != NULL)
           ? wt->node_weights[node - wt->tree->ctree]
           : node->children;
    }
    static inline npy_float64
    get_weight(const WeightedTree *wt, const npy_intp i)
    {
        return (wt->weights != NULL)?wt->weights[i]:1;
    }
};

extern "C" PyObject*
count_neighbors_weighted(const ckdtree *self, const ckdtree *other,
                npy_float64 *self_weights, npy_float64 *other_weights,
                npy_float64 *self_node_weights, npy_float64 *other_node_weights,
                npy_intp n_queries, npy_float64 *real_r, npy_float64 *results,
                const npy_float64 p)
{

    CNBParams params = {0};

    params.r = real_r;
    params.results = (void*) results;

    params.self.tree = self;
    params.other.tree = other;
    if (self_weights) {
        params.self.weights = self_weights;
        params.self.node_weights = self_node_weights;
    }
    if (other_weights) {
        params.other.weights = other_weights;
        params.other.node_weights = other_node_weights;
    }
    /* release the GIL */
    NPY_BEGIN_ALLOW_THREADS
    {
        try {
            count_neighbors<Weighted, npy_float64>(&params, n_queries, p);
        }
        catch(...) {
            translate_cpp_exception_with_gil();
        }
    }
    /* reacquire the GIL */
    NPY_END_ALLOW_THREADS

    if (PyErr_Occurred())
        /* true if a C++ exception was translated */
        return NULL;
    else {
        /* return None if there were no errors */
        Py_RETURN_NONE;
    }
}

<|endoftext|>


<commit_before>/**
 * This file is part of the KDE project
 *
 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
 * Copyright (C) 2003,2004 Stephan Kulow (coolo@kde.org)
 * Copyright (C) 2004 Dirk Mueller ( mueller@kde.org )
 * Copyright 2006, 2007 Leo Savernik (l.savernik@aon.at)
 * Copyright (C) 2010 Milian Wolff <mail@milianw.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

//BEGIN Includes
#include "indenttest.h"

#include "kateview.h"
#include "katedocument.h"
#include "katedocumenthelpers.h"
#include "kateconfig.h"
#include "katecmd.h"
#include "kateglobal.h"
#include <ktexteditor/commandinterface.h>

#include <kapplication.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kmainwindow.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kglobalsettings.h>
#include <kdefakes.h>
#include <kstatusbar.h>
#include <kio/job.h>

#include <memory>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <limits.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>

#include <QtCore/QObject>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
#include <QtCore/QList>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>
#include <QtCore/Q_PID>
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>

#include <QtScript/QScriptEngine>
#include <QTest>
#include <qtest_kde.h>

#include "testutils.h"

QTEST_KDEMAIN(IndentTest, GUI)

/// somepath/kdelibs/part/tests/
const QString srcPath(KDESRCDIR);
const QString testDataPath(KDESRCDIR "../../testdata/indent/");

#define FAILURE( test, comment ) qMakePair<const char*, const char*>( (test), (comment) )

void IndentTest::initTestCase()
{
  KateGlobal::self()->incRef();
  m_toplevel = new KMainWindow();
  m_document = new KateDocument(true, false, false, m_toplevel);
  m_view = static_cast<KateView *>(m_document->widget());
  m_env = new TestScriptEnv(m_document, m_outputWasCustomised);
}

void IndentTest::cleanupTestCase()
{
    KateGlobal::self()->decRef();
}

void IndentTest::getTestData(const QString& indenter)
{
  QTest::addColumn<QString>("testcase");

  // make sure the indenters are valid
  QFile indenterFile(srcPath + "/../script/data/" + indenter + ".js");
  if (!indenterFile.exists()) {
    QSKIP(qPrintable(QString(indenterFile.fileName() + " does not exist")), SkipAll);
  }
  QVERIFY(indenterFile.open(QFile::ReadOnly));
  QScriptValue result = m_env->engine()->evaluate(indenterFile.readAll(), indenterFile.fileName());
  QVERIFY2( !result.isError(), qPrintable(QString(result.toString() + "\nat "
                                          + m_env->engine()->uncaughtExceptionBacktrace().join("\n"))) );

  const QString testDir( testDataPath + indenter + '/' );
  if ( !QFile::exists(testDir) ) {
    QSKIP(qPrintable(QString(testDir + " does not exist")), SkipAll);
  }
  QDirIterator contents( testDir );
  while ( contents.hasNext() ) {
    QString entry = contents.next();
    if ( entry.endsWith('.') ) {
      continue;
    }
    QFileInfo info(entry);
    if ( !info.isDir() ) {
      continue;
    }
    QTest::newRow( info.baseName().toLocal8Bit() ) << info.absoluteFilePath();
  }
}

void IndentTest::runTest(const ExpectedFailures& failures)
{
  if ( !QFile::exists(testDataPath) )
    QSKIP(qPrintable(QString(testDataPath + " does not exist")), SkipAll);

  QFETCH(QString, testcase);

  m_toplevel->resize( 800, 600); // restore size

  // load page
  KUrl url;
  url.setProtocol("file");
  url.setPath(testcase + "/origin");
  m_document->openUrl(url);

  // evaluate test-script
  QFile sourceFile(testcase + "/input.js");
  QVERIFY( sourceFile.open(QFile::ReadOnly) );

  QTextStream stream(&sourceFile);
  stream.setCodec("UTF8");
  QString code = stream.readAll();
  sourceFile.close();

  // Execute script
  QScriptValue result = m_env->engine()->evaluate(code, testcase + "/input.js", 1);
  QVERIFY2( !result.isError(), result.toString().toUtf8().constData() );

  url.setPath(testcase + "/actual");
  m_document->saveAs(url);

  // diff actual and expected
  QProcess diff;
  QStringList args;
  args << "-u" << (testcase + "/expected") << (testcase + "/actual");
  diff.start("diff", args);
  diff.waitForFinished();
  QByteArray out = diff.readAllStandardOutput();
  QByteArray err = diff.readAllStandardError();
  if ( !err.isEmpty() ) {
    qWarning() << err;
  }
  foreach( const Failure& failure, failures ) {
    QEXPECT_FAIL(failure.first, failure.second, Abort);
  }
  QCOMPARE(QString::fromLocal8Bit(out), QString());
  QCOMPARE(diff.exitCode(), EXIT_SUCCESS);

  m_document->closeUrl();
}

void IndentTest::cstyle_data()
{
  getTestData( "cstyle" );
}

void IndentTest::cstyle()
{
  runTest( ExpectedFailures() << FAILURE( "using1", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "using2", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "plist14", "in function signatures it might be wanted to use the indentation of the\n"
                                                     "opening paren instead of just increasing the indentation level like in function calls" )
                              << FAILURE( "switch10", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "switch11", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "visib2", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "visib3", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "plist10", "low low prio, maybe wontfix: if the user wants to add a arg, he should do so and press enter afterwards" )
                              << FAILURE( "switch13", "pure insanity, whoever wrote this test and expects that to be indented properly should stop writing code" )
  );
}

void IndentTest::python_data()
{
    getTestData( "python" );
}

void IndentTest::python()
{
    m_document->config()->setIndentationMode("python");
    runTest( ExpectedFailures() );
}

void IndentTest::haskell_data()
{
  getTestData( "haskell" );
}

void IndentTest::haskell()
{
  runTest( ExpectedFailures() );
}

void IndentTest::ruby_data()
{
  getTestData( "ruby" );
}

void IndentTest::ruby()
{
  runTest( ExpectedFailures() << FAILURE( "block01", "Multiline blocks using {} is not supported" )
                              << FAILURE( "block02", "Multiline blocks using {} is not supported" )
                              << FAILURE( "singleline01", "Single line defs are not supported" )
                              << FAILURE( "singleline02", "Single line defs are not supported" )
                              << FAILURE( "wordlist01", "multiline word list is not supported" )
                              << FAILURE( "wordlist02", "multiline word list is not supported" )
                              << FAILURE( "wordlist11", "multiline word list is not supported" )
                              << FAILURE( "wordlist12", "multiline word list is not supported" )
                              << FAILURE( "wordlist21", "multiline word list is not supported" )
                              << FAILURE( "wordlist22", "multiline word list is not supported" )
                              << FAILURE( "if20", "multi line if assignment is not supported" )
                              << FAILURE( "if21", "multi line if assignment is not supported" )
                              << FAILURE( "if30", "single line if is not supported" )
                              << FAILURE( "if31", "single line if is not supported" )
  );
}

void IndentTest::normal_data()
{
  getTestData( "normal" );
}

void IndentTest::normal()
{
  runTest( ExpectedFailures() << FAILURE( "emptyline1", "is that really what we expect?" )
                              << FAILURE( "emptyline3", "is that really what we expext?" )
  );
}
<commit_msg>SVN_SILENT fix path to indenter scripts<commit_after>/**
 * This file is part of the KDE project
 *
 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
 * Copyright (C) 2003,2004 Stephan Kulow (coolo@kde.org)
 * Copyright (C) 2004 Dirk Mueller ( mueller@kde.org )
 * Copyright 2006, 2007 Leo Savernik (l.savernik@aon.at)
 * Copyright (C) 2010 Milian Wolff <mail@milianw.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

//BEGIN Includes
#include "indenttest.h"

#include "kateview.h"
#include "katedocument.h"
#include "katedocumenthelpers.h"
#include "kateconfig.h"
#include "katecmd.h"
#include "kateglobal.h"
#include <ktexteditor/commandinterface.h>

#include <kapplication.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kaction.h>
#include <kcmdlineargs.h>
#include <kmainwindow.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kglobalsettings.h>
#include <kdefakes.h>
#include <kstatusbar.h>
#include <kio/job.h>

#include <memory>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <limits.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>

#include <QtCore/QObject>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
#include <QtCore/QList>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>
#include <QtCore/Q_PID>
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtCore/QFileInfo>

#include <QtScript/QScriptEngine>
#include <QTest>
#include <qtest_kde.h>

#include "testutils.h"

QTEST_KDEMAIN(IndentTest, GUI)

/// somepath/kdelibs/part/tests/
const QString srcPath(KDESRCDIR);
const QString testDataPath(KDESRCDIR "../../testdata/indent/");

#define FAILURE( test, comment ) qMakePair<const char*, const char*>( (test), (comment) )

void IndentTest::initTestCase()
{
  KateGlobal::self()->incRef();
  m_toplevel = new KMainWindow();
  m_document = new KateDocument(true, false, false, m_toplevel);
  m_view = static_cast<KateView *>(m_document->widget());
  m_env = new TestScriptEnv(m_document, m_outputWasCustomised);
}

void IndentTest::cleanupTestCase()
{
    KateGlobal::self()->decRef();
}

void IndentTest::getTestData(const QString& indenter)
{
  QTest::addColumn<QString>("testcase");

  // make sure the indenters are valid
  QFile indenterFile(srcPath + "/../script/data/indentation/" + indenter + ".js");
  if (!indenterFile.exists()) {
    QSKIP(qPrintable(QString(indenterFile.fileName() + " does not exist")), SkipAll);
  }
  QVERIFY(indenterFile.open(QFile::ReadOnly));
  QScriptValue result = m_env->engine()->evaluate(indenterFile.readAll(), indenterFile.fileName());
  QVERIFY2( !result.isError(), qPrintable(QString(result.toString() + "\nat "
                                          + m_env->engine()->uncaughtExceptionBacktrace().join("\n"))) );

  const QString testDir( testDataPath + indenter + '/' );
  if ( !QFile::exists(testDir) ) {
    QSKIP(qPrintable(QString(testDir + " does not exist")), SkipAll);
  }
  QDirIterator contents( testDir );
  while ( contents.hasNext() ) {
    QString entry = contents.next();
    if ( entry.endsWith('.') ) {
      continue;
    }
    QFileInfo info(entry);
    if ( !info.isDir() ) {
      continue;
    }
    QTest::newRow( info.baseName().toLocal8Bit() ) << info.absoluteFilePath();
  }
}

void IndentTest::runTest(const ExpectedFailures& failures)
{
  if ( !QFile::exists(testDataPath) )
    QSKIP(qPrintable(QString(testDataPath + " does not exist")), SkipAll);

  QFETCH(QString, testcase);

  m_toplevel->resize( 800, 600); // restore size

  // load page
  KUrl url;
  url.setProtocol("file");
  url.setPath(testcase + "/origin");
  m_document->openUrl(url);

  // evaluate test-script
  QFile sourceFile(testcase + "/input.js");
  QVERIFY( sourceFile.open(QFile::ReadOnly) );

  QTextStream stream(&sourceFile);
  stream.setCodec("UTF8");
  QString code = stream.readAll();
  sourceFile.close();

  // Execute script
  QScriptValue result = m_env->engine()->evaluate(code, testcase + "/input.js", 1);
  QVERIFY2( !result.isError(), result.toString().toUtf8().constData() );

  url.setPath(testcase + "/actual");
  m_document->saveAs(url);

  // diff actual and expected
  QProcess diff;
  QStringList args;
  args << "-u" << (testcase + "/expected") << (testcase + "/actual");
  diff.start("diff", args);
  diff.waitForFinished();
  QByteArray out = diff.readAllStandardOutput();
  QByteArray err = diff.readAllStandardError();
  if ( !err.isEmpty() ) {
    qWarning() << err;
  }
  foreach( const Failure& failure, failures ) {
    QEXPECT_FAIL(failure.first, failure.second, Abort);
  }
  QCOMPARE(QString::fromLocal8Bit(out), QString());
  QCOMPARE(diff.exitCode(), EXIT_SUCCESS);

  m_document->closeUrl();
}

void IndentTest::cstyle_data()
{
  getTestData( "cstyle" );
}

void IndentTest::cstyle()
{
  runTest( ExpectedFailures() << FAILURE( "using1", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "using2", "this is insane, those who write such code can cope with it :P" )
                              << FAILURE( "plist14", "in function signatures it might be wanted to use the indentation of the\n"
                                                     "opening paren instead of just increasing the indentation level like in function calls" )
                              << FAILURE( "switch10", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "switch11", "test for case where cfgSwitchIndent = false; needs proper config-interface" )
                              << FAILURE( "visib2", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "visib3", "test for access modifier where cfgAccessModifiers = 1;needs proper config interface" )
                              << FAILURE( "plist10", "low low prio, maybe wontfix: if the user wants to add a arg, he should do so and press enter afterwards" )
                              << FAILURE( "switch13", "pure insanity, whoever wrote this test and expects that to be indented properly should stop writing code" )
  );
}

void IndentTest::python_data()
{
    getTestData( "python" );
}

void IndentTest::python()
{
    m_document->config()->setIndentationMode("python");
    runTest( ExpectedFailures() );
}

void IndentTest::haskell_data()
{
  getTestData( "haskell" );
}

void IndentTest::haskell()
{
  runTest( ExpectedFailures() );
}

void IndentTest::ruby_data()
{
  getTestData( "ruby" );
}

void IndentTest::ruby()
{
  runTest( ExpectedFailures() << FAILURE( "block01", "Multiline blocks using {} is not supported" )
                              << FAILURE( "block02", "Multiline blocks using {} is not supported" )
                              << FAILURE( "singleline01", "Single line defs are not supported" )
                              << FAILURE( "singleline02", "Single line defs are not supported" )
                              << FAILURE( "wordlist01", "multiline word list is not supported" )
                              << FAILURE( "wordlist02", "multiline word list is not supported" )
                              << FAILURE( "wordlist11", "multiline word list is not supported" )
                              << FAILURE( "wordlist12", "multiline word list is not supported" )
                              << FAILURE( "wordlist21", "multiline word list is not supported" )
                              << FAILURE( "wordlist22", "multiline word list is not supported" )
                              << FAILURE( "if20", "multi line if assignment is not supported" )
                              << FAILURE( "if21", "multi line if assignment is not supported" )
                              << FAILURE( "if30", "single line if is not supported" )
                              << FAILURE( "if31", "single line if is not supported" )
  );
}

void IndentTest::normal_data()
{
  getTestData( "normal" );
}

void IndentTest::normal()
{
  runTest( ExpectedFailures() << FAILURE( "emptyline1", "is that really what we expect?" )
                              << FAILURE( "emptyline3", "is that really what we expext?" )
  );
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-cstable/StringColumnWriter.h>

namespace fnord {
namespace cstable {

StringColumnWriter::StringColumnWriter(
    uint64_t r_max,
    uint64_t d_max,
    size_t max_strlen) :
    ColumnWriter(r_max, d_max),
    max_strlen_(max_strlen) {}

void StringColumnWriter::addDatum(
    uint64_t rep_level,
    uint64_t def_level,
    const String& value) {
  rlvl_writer_.encode(rep_level);
  dlvl_writer_.encode(def_level);
  data_writer_.appendUInt32(value.size());
  data_writer_.append(value.data(), value.size());
}

void StringColumnWriter::write(util::BinaryMessageWriter* writer) {
  writer->append(data_writer_.data(), data_writer_.size());
}

size_t StringColumnWriter::size() const {
  return data_writer_.size();
}

} // namespace cstable
} // namespace fnord
<commit_msg>write empty strings as NULL in StringColumnWriter<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-cstable/StringColumnWriter.h>

namespace fnord {
namespace cstable {

StringColumnWriter::StringColumnWriter(
    uint64_t r_max,
    uint64_t d_max,
    size_t max_strlen) :
    ColumnWriter(r_max, d_max),
    max_strlen_(max_strlen) {}

void StringColumnWriter::addDatum(
    uint64_t rep_level,
    uint64_t def_level,
    const String& value) {
  if (value.length() == 0) {
    addNull(rep_level, def_level);
    return;
  }

  rlvl_writer_.encode(rep_level);
  dlvl_writer_.encode(def_level);
  data_writer_.appendUInt32(value.size());
  data_writer_.append(value.data(), value.size());
}

void StringColumnWriter::write(util::BinaryMessageWriter* writer) {
  writer->append(data_writer_.data(), data_writer_.size());
}

size_t StringColumnWriter::size() const {
  return data_writer_.size();
}

} // namespace cstable
} // namespace fnord
<|endoftext|>


<commit_before>// this file defines the otbCommonTest for the test driver
// and all it expects is that you have a function called RegisterTests
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include <iostream>
#include "otbTestMain.h"

void RegisterTests()
{
REGISTER_TEST(otbExtractROI);
REGISTER_TEST(otbExtractROI_RGB);
REGISTER_TEST(otbMultiChannelExtractROI );
REGISTER_TEST(otbMultiToMonoChannelExtractROI );
REGISTER_TEST(otbLineSpatialObjectList);
REGISTER_TEST(otbPointSetSourceTest);
//REGISTER_TEST(otbDrawLineSpatialObjectNew);
//REGISTER_TEST(otbDrawLineSpatialObject);
//REGISTER_TEST(otbDrawLineSpatialObjectListNew);
}
<commit_msg>nomsg<commit_after>// this file defines the otbCommonTest for the test driver
// and all it expects is that you have a function called RegisterTests
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include <iostream>
#include "otbTestMain.h"

void RegisterTests()
{
REGISTER_TEST(otbExtractROI);
REGISTER_TEST(otbExtractROI_RGB);
REGISTER_TEST(otbMultiChannelExtractROI );
REGISTER_TEST(otbMultiToMonoChannelExtractROI );
REGISTER_TEST(otbLineSpatialObjectList);
REGISTER_TEST(otbPointSetSourceTest);
//REGISTER_TEST(otbDrawLineSpatialObjectNew);
//REGISTER_TEST(otbDrawLineSpatialObject);
//REGISTER_TEST(otbDrawLineSpatialObjectListNew);
REGISTER_TEST(otbDrawLineSpatialObjectList);
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------------------------*\
 |                                                                          |
 |  Copyright (C) 2017                                                      |
 |                                                                          |
 |         , __                 , __                                        |
 |        /|/  \               /|/  \                                       |
 |         | __/ _   ,_         | __/ _   ,_                                |
 |         |   \|/  /  |  |   | |   \|/  /  |  |   |                        |
 |         |(__/|__/   |_/ \_/|/|(__/|__/   |_/ \_/|/                       |
 |                           /|                   /|                        |
 |                           \|                   \|                        |
 |                                                                          |
 |      Enrico Bertolazzi                                                   |
 |      Dipartimento di Ingegneria Industriale                              |
 |      Universita` degli Studi di Trento                                   |
 |      email: enrico.bertolazzi@unitn.it                                   |
 |                                                                          |
\*--------------------------------------------------------------------------*/

#include "Clothoid.hh"

#include <cmath>
#include <cfloat>

namespace Clothoid {

  using namespace std ;

  /*\
   |   ____ _       _   _           _     _ _     _     _
   |  / ___| | ___ | |_| |__   ___ (_) __| | |   (_)___| |_
   | | |   | |/ _ \| __| '_ \ / _ \| |/ _` | |   | / __| __|
   | | |___| | (_) | |_| | | | (_) | | (_| | |___| \__ \ |_
   |  \____|_|\___/ \__|_| |_|\___/|_|\__,_|_____|_|___/\__|
   |
  \*/

  ClothoidList::~ClothoidList() {
    s0.clear() ;
    clotoidList.clear();
  }

  void
  ClothoidList::copy( ClothoidList const & L ) {
    s0.resize( L.s0.size() ) ;
    std::copy( L.s0.begin(), L.s0.end(), s0.begin() ) ;
    clotoidList.resize( L.clotoidList.size() ) ;
    std::copy( L.clotoidList.begin(), L.clotoidList.end(), clotoidList.begin() ) ;
  }

  void
  ClothoidList::reserve( indexType n ) {
    s0.reserve(size_t(n+1)) ;
    clotoidList.reserve(size_t(n)) ;
  }

  void
  ClothoidList::add( ClothoidCurve const & c ) {
    if ( clotoidList.empty() ) {
      s0.push_back(0) ;
      s0.push_back(c.getL()) ;
    } else {
      s0.push_back(s0.back()+c.getL()) ;
    }
    clotoidList.push_back(c) ;
  }

  ClothoidCurve const &
  ClothoidList::get( indexType idx ) const {
    G2LIB_ASSERT( !clotoidList.empty(), "ClothoidList::get( " << idx << " ) empty list" );
    G2LIB_ASSERT( idx >= 0 && idx < indexType(clotoidList.size()),
                  "ClothoidList::get( " << idx << " ) bad index" );
    return clotoidList[idx];
  }

  ClothoidCurve const &
  ClothoidList::getAtS( valueType s, indexType & last_idx ) const {
    findAtS(s,last_idx);
    return get(last_idx) ;
  }

  bool
  ClothoidList::findAtS( valueType s, indexType & last_idx ) const {
    indexType ns = indexType(clotoidList.size()) ;
    G2LIB_ASSERT( last_idx >= 0 && last_idx < ns,
                  "ClothoidList::findAtS( " << s << ", " << last_idx <<
                  " ) bad index" );
    valueType const * sL = &s0[last_idx] ;
    if ( s < sL[0] ) {
      valueType const * sB = &s0.front() ;
      last_idx = indexType(std::lower_bound( sB, sL, s )-sB) ;
    } else if ( s > sL[1] ) {
      valueType const * sE = &s0[ns+1] ;
      last_idx += indexType(std::lower_bound( sL, sE, s )-sL) ;
    } else {
      return true ; // vale intervallo precedente
    }
    if ( s0[last_idx] > s ) --last_idx ; // aggiustamento caso di bordo
    return true ;
  }

  valueType
  ClothoidList::theta( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::theta_D( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta_D( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::theta_DD( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta_DD( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::X( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.X( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::Y( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.Y( s - s0[last_idx] ) ;
  }

  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType & theta,
                      valueType & kappa,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], theta, kappa, x, y ) ;
  }

  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], x, y ) ;
  }

  void
  ClothoidList::eval_D( valueType   s,
                        indexType & last_idx,
                        valueType & x_D,
                        valueType & y_D ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_D( s - s0[last_idx], x_D, y_D ) ;
  }

  void
  ClothoidList::eval_DD( valueType   s,
                         indexType & last_idx,
                         valueType & x_DD,
                         valueType & y_DD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DD( s - s0[last_idx], x_DD, y_DD ) ;
  }

  void
  ClothoidList::eval_DDD( valueType   s,
                          indexType & last_idx,
                          valueType & x_DDD,
                          valueType & y_DDD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DDD( s - s0[last_idx], x_DDD, y_DDD ) ;
  }

  // offset curve
  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType   offs,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], offs, x, y ) ;
  }

  void
  ClothoidList::eval_D( valueType   s,
                        indexType & last_idx,
                        valueType   offs,
                        valueType & x_D,
                        valueType & y_D ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_D( s - s0[last_idx], offs, x_D, y_D ) ;
  }

  void
  ClothoidList::eval_DD( valueType   s,
                         indexType & last_idx,
                         valueType   offs,
                         valueType & x_DD,
                         valueType & y_DD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DD( s - s0[last_idx], offs, x_DD, y_DD ) ;
  }

  void
  ClothoidList::eval_DDD( valueType   s,
                          indexType & last_idx,
                          valueType   offs,
                          valueType & x_DDD,
                          valueType & y_DDD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DDD( s - s0[last_idx], offs, x_DDD, y_DDD ) ;
  }

  valueType
  ClothoidList::closestPoint( valueType   x,
                              valueType   y,
                              valueType   ds,
                              valueType & X,
                              valueType & Y,
                              valueType & S ) const {
    G2LIB_ASSERT( !clotoidList.empty(), "ClothoidList::closestPoint, empty list" );
    std::vector<ClothoidCurve>::const_iterator ic = clotoidList.begin() ;
    std::vector<valueType>::const_iterator     is = s0.begin() ;
    valueType DST = ic->closestPoint( x, y, ds, X, Y, S );
    for ( ++ic, ++is ; ic != clotoidList.end() ; ++ic, ++is ) {
      valueType X1, Y1, S1 ;
      valueType DST1 = ic->closestPoint( x, y, ds, X1, Y1, S1 );
      if ( DST1 < DST ) {
        DST = DST1 ;
        X   = X1;
        Y   = Y1;
        S   = *is + S1;
      }
    }
    return DST ;
  }

  void
  ClothoidList::rotate( valueType angle, valueType cx, valueType cy ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->rotate( angle, cx, cy ) ;
  }

  void
  ClothoidList::translate( valueType tx, valueType ty ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->translate( tx, ty ) ;
  }

  void
  ClothoidList::moveOrigin( valueType newx0, valueType newy0 ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) {
      ic->moveOrigin( newx0, newy0 ) ;
      newx0 = ic->Xend() ;
      newy0 = ic->Yend() ;
    }
  }

  void
  ClothoidList::scale( valueType sfactor ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    valueType newx0 = ic->Xbegin() ;
    valueType newy0 = ic->Ybegin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) {
      ic->scale( sfactor ) ;
      ic->moveOrigin( newx0, newy0 ) ;
      newx0 = ic->Xend() ;
      newy0 = ic->Yend() ;
    }
  }

  void
  ClothoidList::reverse() {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->reverse() ;
    std::reverse( clotoidList.begin(), clotoidList.end() );
  }
}

// EOF: ClothoidList.cc
<commit_msg>added missing include<commit_after>/*--------------------------------------------------------------------------*\
 |                                                                          |
 |  Copyright (C) 2017                                                      |
 |                                                                          |
 |         , __                 , __                                        |
 |        /|/  \               /|/  \                                       |
 |         | __/ _   ,_         | __/ _   ,_                                |
 |         |   \|/  /  |  |   | |   \|/  /  |  |   |                        |
 |         |(__/|__/   |_/ \_/|/|(__/|__/   |_/ \_/|/                       |
 |                           /|                   /|                        |
 |                           \|                   \|                        |
 |                                                                          |
 |      Enrico Bertolazzi                                                   |
 |      Dipartimento di Ingegneria Industriale                              |
 |      Universita` degli Studi di Trento                                   |
 |      email: enrico.bertolazzi@unitn.it                                   |
 |                                                                          |
\*--------------------------------------------------------------------------*/

#include "Clothoid.hh"

#include <cmath>
#include <cfloat>
#include <algorithm>

namespace Clothoid {

  using namespace std ;

  /*\
   |   ____ _       _   _           _     _ _     _     _
   |  / ___| | ___ | |_| |__   ___ (_) __| | |   (_)___| |_
   | | |   | |/ _ \| __| '_ \ / _ \| |/ _` | |   | / __| __|
   | | |___| | (_) | |_| | | | (_) | | (_| | |___| \__ \ |_
   |  \____|_|\___/ \__|_| |_|\___/|_|\__,_|_____|_|___/\__|
   |
  \*/

  ClothoidList::~ClothoidList() {
    s0.clear() ;
    clotoidList.clear();
  }

  void
  ClothoidList::copy( ClothoidList const & L ) {
    s0.resize( L.s0.size() ) ;
    std::copy( L.s0.begin(), L.s0.end(), s0.begin() ) ;
    clotoidList.resize( L.clotoidList.size() ) ;
    std::copy( L.clotoidList.begin(), L.clotoidList.end(), clotoidList.begin() ) ;
  }

  void
  ClothoidList::reserve( indexType n ) {
    s0.reserve(size_t(n+1)) ;
    clotoidList.reserve(size_t(n)) ;
  }

  void
  ClothoidList::add( ClothoidCurve const & c ) {
    if ( clotoidList.empty() ) {
      s0.push_back(0) ;
      s0.push_back(c.getL()) ;
    } else {
      s0.push_back(s0.back()+c.getL()) ;
    }
    clotoidList.push_back(c) ;
  }

  ClothoidCurve const &
  ClothoidList::get( indexType idx ) const {
    G2LIB_ASSERT( !clotoidList.empty(), "ClothoidList::get( " << idx << " ) empty list" );
    G2LIB_ASSERT( idx >= 0 && idx < indexType(clotoidList.size()),
                  "ClothoidList::get( " << idx << " ) bad index" );
    return clotoidList[idx];
  }

  ClothoidCurve const &
  ClothoidList::getAtS( valueType s, indexType & last_idx ) const {
    findAtS(s,last_idx);
    return get(last_idx) ;
  }

  bool
  ClothoidList::findAtS( valueType s, indexType & last_idx ) const {
    indexType ns = indexType(clotoidList.size()) ;
    G2LIB_ASSERT( last_idx >= 0 && last_idx < ns,
                  "ClothoidList::findAtS( " << s << ", " << last_idx <<
                  " ) bad index" );
    valueType const * sL = &s0[last_idx] ;
    if ( s < sL[0] ) {
      valueType const * sB = &s0.front() ;
      last_idx = indexType(std::lower_bound( sB, sL, s )-sB) ;
    } else if ( s > sL[1] ) {
      valueType const * sE = &s0[ns+1] ;
      last_idx += indexType(std::lower_bound( sL, sE, s )-sL) ;
    } else {
      return true ; // vale intervallo precedente
    }
    if ( s0[last_idx] > s ) --last_idx ; // aggiustamento caso di bordo
    return true ;
  }

  valueType
  ClothoidList::theta( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::theta_D( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta_D( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::theta_DD( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.theta_DD( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::X( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.X( s - s0[last_idx] ) ;
  }

  valueType
  ClothoidList::Y( valueType s, indexType & last_idx ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.Y( s - s0[last_idx] ) ;
  }

  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType & theta,
                      valueType & kappa,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], theta, kappa, x, y ) ;
  }

  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], x, y ) ;
  }

  void
  ClothoidList::eval_D( valueType   s,
                        indexType & last_idx,
                        valueType & x_D,
                        valueType & y_D ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_D( s - s0[last_idx], x_D, y_D ) ;
  }

  void
  ClothoidList::eval_DD( valueType   s,
                         indexType & last_idx,
                         valueType & x_DD,
                         valueType & y_DD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DD( s - s0[last_idx], x_DD, y_DD ) ;
  }

  void
  ClothoidList::eval_DDD( valueType   s,
                          indexType & last_idx,
                          valueType & x_DDD,
                          valueType & y_DDD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DDD( s - s0[last_idx], x_DDD, y_DDD ) ;
  }

  // offset curve
  void
  ClothoidList::eval( valueType   s,
                      indexType & last_idx,
                      valueType   offs,
                      valueType & x,
                      valueType & y ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval( s - s0[last_idx], offs, x, y ) ;
  }

  void
  ClothoidList::eval_D( valueType   s,
                        indexType & last_idx,
                        valueType   offs,
                        valueType & x_D,
                        valueType & y_D ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_D( s - s0[last_idx], offs, x_D, y_D ) ;
  }

  void
  ClothoidList::eval_DD( valueType   s,
                         indexType & last_idx,
                         valueType   offs,
                         valueType & x_DD,
                         valueType & y_DD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DD( s - s0[last_idx], offs, x_DD, y_DD ) ;
  }

  void
  ClothoidList::eval_DDD( valueType   s,
                          indexType & last_idx,
                          valueType   offs,
                          valueType & x_DDD,
                          valueType & y_DDD ) const {
    findAtS( s, last_idx );
    ClothoidCurve const & c = get( last_idx );
    return c.eval_DDD( s - s0[last_idx], offs, x_DDD, y_DDD ) ;
  }

  valueType
  ClothoidList::closestPoint( valueType   x,
                              valueType   y,
                              valueType   ds,
                              valueType & X,
                              valueType & Y,
                              valueType & S ) const {
    G2LIB_ASSERT( !clotoidList.empty(), "ClothoidList::closestPoint, empty list" );
    std::vector<ClothoidCurve>::const_iterator ic = clotoidList.begin() ;
    std::vector<valueType>::const_iterator     is = s0.begin() ;
    valueType DST = ic->closestPoint( x, y, ds, X, Y, S );
    for ( ++ic, ++is ; ic != clotoidList.end() ; ++ic, ++is ) {
      valueType X1, Y1, S1 ;
      valueType DST1 = ic->closestPoint( x, y, ds, X1, Y1, S1 );
      if ( DST1 < DST ) {
        DST = DST1 ;
        X   = X1;
        Y   = Y1;
        S   = *is + S1;
      }
    }
    return DST ;
  }

  void
  ClothoidList::rotate( valueType angle, valueType cx, valueType cy ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->rotate( angle, cx, cy ) ;
  }

  void
  ClothoidList::translate( valueType tx, valueType ty ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->translate( tx, ty ) ;
  }

  void
  ClothoidList::moveOrigin( valueType newx0, valueType newy0 ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) {
      ic->moveOrigin( newx0, newy0 ) ;
      newx0 = ic->Xend() ;
      newy0 = ic->Yend() ;
    }
  }

  void
  ClothoidList::scale( valueType sfactor ) {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    valueType newx0 = ic->Xbegin() ;
    valueType newy0 = ic->Ybegin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) {
      ic->scale( sfactor ) ;
      ic->moveOrigin( newx0, newy0 ) ;
      newx0 = ic->Xend() ;
      newy0 = ic->Yend() ;
    }
  }

  void
  ClothoidList::reverse() {
    std::vector<ClothoidCurve>::iterator ic = clotoidList.begin() ;
    for ( ; ic != clotoidList.end() ; ++ic ) ic->reverse() ;
    std::reverse( clotoidList.begin(), clotoidList.end() );
  }
}

// EOF: ClothoidList.cc
<|endoftext|>