<commit_before>// Copyright 2013-2015 Eric Schkufza, Rahul Sharma, Berkeley Churchill, Stefan Heule
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cmath>

#include <algorithm>
#include <array>
#include <limits>

#include "src/cost/cost_function.h"
#include "src/ext/x64asm/include/x64asm.h"

using namespace cpputil;
using namespace std;
using namespace x64asm;

namespace {

array<stoke::Cost, 3976> latencies_ {{
#include "src/cost/tables/haswell_latency.h"
  }
};

} // namespace

namespace stoke {

CostFunction& CostFunction::set_target(const Cfg& target, bool stack_out, bool heap_out) {
  assert(sandbox_ != nullptr);

  live_out_ = target.live_outs();
  stack_out_ = stack_out;
  heap_out_ = heap_out;

  reference_out_.clear();
  recompute_defs(target.live_outs(), target_gp_out_, target_sse_out_);

  sandbox_->run(target);
  for (auto i = sandbox_->result_begin(), ie = sandbox_->result_end(); i != ie; ++i) {
    reference_out_.push_back(*i);
  }
  return *this;
}

void CostFunction::recompute_defs(const RegSet& rs, vector<R64>& gps, vector<Xmm>& sses) {
  gps.clear();
  for (const auto& r : rls) {
    if (rs.contains(r)) {
      gps.push_back(r64s[r]);
    }
  }
  for (const auto& r : rbs) {
    if (rs.contains(r)) {
      gps.push_back(r64s[r]);
    }
  }

  sses.clear();
  for (const auto& s : xmms) {
    if (rs.contains(s)) {
      sses.push_back(s);
    }
  }
}

/** Evaluate a rewrite. This method may shortcircuit and return max as soon as its
  result would equal or exceed that value. */
CostFunction::result_type CostFunction::operator()(const Cfg& cfg, const Cost max) {

  auto cost = k_ * evaluate_correctness(cfg, (max + k_ - 1) / k_);
  assert(cost <= max_cost);

  const auto correct = cost == 0;
  if (cost < max && pterm_ != PerformanceTerm::NONE) {
    cost += evaluate_performance(cfg, max);
  }
  assert(cost <= max_cost);

  return result_type(correct, cost);
}

Cost CostFunction::evaluate_correctness(const Cfg& cfg, const Cost max) {

  // Apply the size penalty if needed
  Cost penalty = 0;
  if (size_starting_penalty_ > 0 || size_incr_penalty_ > 0) {
    penalty = assembled_size_cost(cfg);
    if (penalty >= max) {
      return max;
    }
  }

  switch (reduction_) {
  case Reduction::MAX:
    return penalty + max_correctness(cfg, max - penalty);
  case Reduction::SUM:
    return penalty + sum_correctness(cfg, max - penalty);
  case Reduction::EXTENSION:
    return penalty + extension_correctness(cfg, max - penalty);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::max_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  sandbox_->compile(cfg);
  recompute_defs(cfg.def_outs(), rewrite_gp_out_, rewrite_sse_out_);

  size_t i = 0;
  for (size_t ie = sandbox_->size(); res < max && i < ie; ++i) {
    sandbox_->run_one(i);
    res = std::max(res, evaluate_error(reference_out_[i], *(sandbox_->get_result(i))));
    assert(res <= max_testcase_cost);
  }

  assert(res <= max_correctness_cost);
  return res;
}

Cost CostFunction::sum_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  sandbox_->compile(cfg);
  recompute_defs(cfg.def_outs(), rewrite_gp_out_, rewrite_sse_out_);

  size_t i = 0;
  for (size_t ie = sandbox_->size(); res < max && i < ie; ++i) {
    sandbox_->run_one(i);
    const auto err = evaluate_error(reference_out_[i], *(sandbox_->get_result(i)));
    assert(err <= max_testcase_cost);

    res += err;
  }

  assert(res <= max_correctness_cost);
  return res;
}

Cost CostFunction::extension_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  // Add user-defined implementation here ...

  // This method is not required to examine all testcases. Implementations
  // that compute res iteratively may stop executing and return max once res
  // equals or exceeds that value.

  // Invariant 1: Return value should not exceed max_correctness_cost
  assert(res <= max_correctness_cost);

  return res;
}

Cost CostFunction::evaluate_error(const CpuState& t, const CpuState& r) const {
  if (t.code != r.code) {
    return sig_penalty_;
  }

  Cost cost = 0;
  cost += gp_error(t.gp, r.gp);
  cost += sse_error(t.sse, r.sse);
  cost += rflags_error(t.rf, r.rf);
  if (stack_out_) {
    cost += mem_error(t.stack, r.stack);
  }
  if (heap_out_) {
    cost += mem_error(t.heap, r.heap);
  }

  return cost;
}

Cost CostFunction::gp_error(const Regs& t, const Regs& r) const {
  Cost cost = 0;

  for (const auto& r_t : target_gp_out_) {
    auto delta = max_error_cost;
    const auto val_t = t[r_t].get_fixed_quad(0);

    for (const auto& r_r : rewrite_gp_out_) {
      if (r_t != r_r && !relax_reg_) {
        continue;
      }

      const auto val_r = r[r_r].get_fixed_quad(0);
      const auto eval = evaluate_distance(val_t, val_r) + ((r_t == r_r) ? 0 : misalign_penalty_);

      delta = min(delta, eval);
    }
    cost += delta;
  }

  return cost;
}

Cost CostFunction::sse_error(const Regs& t, const Regs& r) const {
  Cost cost = 0;

  for (size_t i = 0; i < sse_count_; ++i) {
    for (const auto& s_t : target_sse_out_) {
      auto delta = max_error_cost;
      uint64_t val_t = 0;
      switch (sse_width_) {
      case 1:
        val_t = t[s_t].get_fixed_byte(i);
        break;
      case 2:
        val_t = t[s_t].get_fixed_word(i);
        break;
      case 4:
        val_t = t[s_t].get_fixed_double(i);
        break;
      case 8:
        val_t = t[s_t].get_fixed_quad(i);
        break;
      default:
        assert(false);
        break;
      }

      for (const auto& s_r : rewrite_sse_out_) {
        if (s_t != s_r && !relax_reg_) {
          continue;
        }

        uint64_t val_r = 0;
        switch (sse_width_) {
        case 1:
          val_r = r[s_r].get_fixed_byte(i);
          break;
        case 2:
          val_r = r[s_r].get_fixed_word(i);
          break;
        case 4:
          val_r = r[s_r].get_fixed_double(i);
          break;
        case 8:
          val_r = r[s_r].get_fixed_quad(i);
          break;
        default:
          assert(false);
          break;
        }

        const auto eval = evaluate_distance(val_t, val_r) + ((s_t == s_r) ? 0 : misalign_penalty_);
        delta = min(delta, eval);
      }
      cost += delta;
    }
  }

  return cost;
}

Cost CostFunction::mem_error(const Memory& t, const Memory& r) const {
  Cost cost = 0;

  for (auto i = t.defined_begin(), ie = t.defined_end(); i != ie; ++i) {
    if (relax_mem_) {
      Cost delta = max_error_cost;
      for (auto j = r.defined_begin(), je = r.defined_end(); j != je; ++j) {
        const auto eval = evaluate_distance(t[*i], r[*j]) + (*i == *j ? 0 : misalign_penalty_);
        delta = min(delta, eval);
      }
      cost += delta;
    } else {
      cost += r.is_defined(*i) ? evaluate_distance(t[*i], r[*i]) : max_error_cost;
    }
  }

  return cost;
}

Cost CostFunction::rflags_error(const RFlags& t, const RFlags& r) const {
  Cost cost = 0;

  auto flags = vector<Eflags> { eflags_cf, eflags_pf, eflags_af, eflags_zf, eflags_of, eflags_sf };

  for (auto flag : flags) {
    if (live_out_.contains(flag)) {
      size_t i = flag.index();
      cost += (t.is_set(i) ^ r.is_set(i));
    }
  }

  return cost;
}

Cost CostFunction::assembled_size_cost(const Cfg& cfg) const {

  x64asm::Assembler assm;
  x64asm::Function fxn;

  const auto& code = cfg.get_code();

  assm.start(fxn);

  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {

    if (cfg.is_exit(*b)) {
      continue;
    }

    const auto begin = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = 0, ie = begin + cfg.num_instrs(*b); i < ie; ++i) {
      const auto& instr = code[i];
      if (!instr.is_nop() && !instr.is_ret()) {
        assm.assemble(instr);
      }
    }
  }

  assm.finish();

  uint64_t size = fxn.size();
  if (size <= max_size_) {
    return 0;
  } else {
    return (Cost)((size - max_size_) * size_incr_penalty_ + size_starting_penalty_);
  }

}

Cost CostFunction::evaluate_distance(uint64_t x, uint64_t y) const {
  switch (distance_) {
  case Distance::HAMMING:
    return hamming_distance(x, y);
  case Distance::ULP:
    return ulp_distance(x, y);
  case Distance::EXTENSION:
    return extension_distance(x, y);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::ulp_distance(uint64_t x, uint64_t y) const {
  auto t = *((int64_t*)&x);
  t = t < 0 ? numeric_limits<int64_t>::min() - t : t;

  auto r = *((int64_t*)&y);
  r = r < 0 ? numeric_limits<int64_t>::min() - r : r;

  uint64_t ulp = t >= r ? t - r : r - t;
  ulp = ulp < min_ulp_ ? 0 : ulp - min_ulp_;

  return ulp > max_error_cost ? max_error_cost : ulp;
}

Cost CostFunction::extension_distance(uint64_t x, uint64_t y) const {
  Cost res = 0;

  // Add user-defined implementation here ...

  // Invariant 1: Return value should not exceed max_error_cost

  return res;
}

Cost CostFunction::evaluate_performance(const Cfg& cfg, const Cost max) const {
  switch (pterm_) {
  case PerformanceTerm::SIZE:
    return size_performance(cfg);
  case PerformanceTerm::LATENCY:
    return latency_performance(cfg);
  case PerformanceTerm::EXTENSION:
    return extension_performance(cfg);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::size_performance(const Cfg& cfg) const {
  Cost size = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      if (!code[i].is_nop()) {
        size++;
      }
    }
  }

  return size;
}

Cost CostFunction::latency_performance(const Cfg& cfg) const {
  Cost latency = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    Cost block_latency = 0;
    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      if (!code[i].is_nop()) {
        block_latency += latencies_[code[i].get_opcode()];
      }
    }

    latency += block_latency * pow(nesting_penalty_, cfg.nesting_depth(*b));
  }

  return latency;
}

Cost CostFunction::extension_performance(const Cfg& cfg) const {
  Cost res = 0;

  // Add user-defined implementation here ...

  // Invariant: Return value should not exceed max_performance_cost
  assert(res <= max_performance_cost);

  return res;
}

} // namespace stoke
<commit_msg>Fixes #335 Merge branch 'release-2.0' into issue-350<commit_after>// Copyright 2013-2015 Eric Schkufza, Rahul Sharma, Berkeley Churchill, Stefan Heule
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cmath>

#include <algorithm>
#include <array>
#include <limits>

#include "src/cost/cost_function.h"
#include "src/ext/x64asm/include/x64asm.h"

using namespace cpputil;
using namespace std;
using namespace x64asm;

namespace {

array<stoke::Cost, 3976> latencies_ {{
#include "src/cost/tables/haswell_latency.h"
  }
};

} // namespace

namespace stoke {

CostFunction& CostFunction::set_target(const Cfg& target, bool stack_out, bool heap_out) {
  assert(sandbox_ != nullptr);

  live_out_ = target.live_outs();
  stack_out_ = stack_out;
  heap_out_ = heap_out;

  reference_out_.clear();
  recompute_defs(target.live_outs(), target_gp_out_, target_sse_out_);

  sandbox_->run(target);
  for (auto i = sandbox_->result_begin(), ie = sandbox_->result_end(); i != ie; ++i) {
    reference_out_.push_back(*i);
  }
  return *this;
}

void CostFunction::recompute_defs(const RegSet& rs, vector<R64>& gps, vector<Xmm>& sses) {
  gps.clear();
  for (const auto& r : rls) {
    if (rs.contains(r)) {
      gps.push_back(r64s[r]);
    }
  }
  for (const auto& r : rbs) {
    if (rs.contains(r)) {
      gps.push_back(r64s[r]);
    }
  }

  sses.clear();
  for (const auto& s : xmms) {
    if (rs.contains(s)) {
      sses.push_back(s);
    }
  }
}

/** Evaluate a rewrite. This method may shortcircuit and return max as soon as its
  result would equal or exceed that value. */
CostFunction::result_type CostFunction::operator()(const Cfg& cfg, const Cost max) {

  auto cost = k_ * evaluate_correctness(cfg, (max + k_ - 1) / k_);
  assert(cost <= max_cost);

  const auto correct = cost == 0;
  if (cost < max && pterm_ != PerformanceTerm::NONE) {
    cost += evaluate_performance(cfg, max);
  }
  assert(cost <= max_cost);

  return result_type(correct, cost);
}

Cost CostFunction::evaluate_correctness(const Cfg& cfg, const Cost max) {

  // Apply the size penalty if needed
  Cost penalty = 0;
  if (size_starting_penalty_ > 0 || size_incr_penalty_ > 0) {
    penalty = assembled_size_cost(cfg);
    if (penalty >= max) {
      return max;
    }
  }

  switch (reduction_) {
  case Reduction::MAX:
    return penalty + max_correctness(cfg, max - penalty);
  case Reduction::SUM:
    return penalty + sum_correctness(cfg, max - penalty);
  case Reduction::EXTENSION:
    return penalty + extension_correctness(cfg, max - penalty);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::max_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  sandbox_->compile(cfg);
  recompute_defs(cfg.def_outs(), rewrite_gp_out_, rewrite_sse_out_);

  size_t i = 0;
  for (size_t ie = sandbox_->size(); res < max && i < ie; ++i) {
    sandbox_->run_one(i);
    res = std::max(res, evaluate_error(reference_out_[i], *(sandbox_->get_result(i))));
    assert(res <= max_testcase_cost);
  }

  assert(res <= max_correctness_cost);
  return res;
}

Cost CostFunction::sum_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  sandbox_->compile(cfg);
  recompute_defs(cfg.def_outs(), rewrite_gp_out_, rewrite_sse_out_);

  size_t i = 0;
  for (size_t ie = sandbox_->size(); res < max && i < ie; ++i) {
    sandbox_->run_one(i);
    const auto err = evaluate_error(reference_out_[i], *(sandbox_->get_result(i)));
    assert(err <= max_testcase_cost);

    res += err;
  }

  assert(res <= max_correctness_cost);
  return res;
}

Cost CostFunction::extension_correctness(const Cfg& cfg, const Cost max) {
  Cost res = 0;

  // Add user-defined implementation here ...

  // This method is not required to examine all testcases. Implementations
  // that compute res iteratively may stop executing and return max once res
  // equals or exceeds that value.

  // Invariant 1: Return value should not exceed max_correctness_cost
  assert(res <= max_correctness_cost);

  return res;
}

Cost CostFunction::evaluate_error(const CpuState& t, const CpuState& r) const {
  // Only assess a signal penalty if target and rewrite disagree
  if (t.code != r.code) {
    return sig_penalty_;
  }
  // If this testcase has signalled, we can't guarantee register state --
  // and technically we can do whatever we want with signalling code -- so
  // just return zero cost
  if (t.code != ErrorCode::NORMAL) {
    return 0;
  }

  // Otherwise, we can do the usual thing and check results register by register
  Cost cost = 0;
  cost += gp_error(t.gp, r.gp);
  cost += sse_error(t.sse, r.sse);
  cost += rflags_error(t.rf, r.rf);
  if (stack_out_) {
    cost += mem_error(t.stack, r.stack);
  }
  if (heap_out_) {
    cost += mem_error(t.heap, r.heap);
  }

  return cost;
}

Cost CostFunction::gp_error(const Regs& t, const Regs& r) const {
  Cost cost = 0;

  for (const auto& r_t : target_gp_out_) {
    auto delta = max_error_cost;
    const auto val_t = t[r_t].get_fixed_quad(0);

    for (const auto& r_r : rewrite_gp_out_) {
      if (r_t != r_r && !relax_reg_) {
        continue;
      }

      const auto val_r = r[r_r].get_fixed_quad(0);
      const auto eval = evaluate_distance(val_t, val_r) + ((r_t == r_r) ? 0 : misalign_penalty_);

      delta = min(delta, eval);
    }
    cost += delta;
  }

  return cost;
}

Cost CostFunction::sse_error(const Regs& t, const Regs& r) const {
  Cost cost = 0;

  for (size_t i = 0; i < sse_count_; ++i) {
    for (const auto& s_t : target_sse_out_) {
      auto delta = max_error_cost;
      uint64_t val_t = 0;
      switch (sse_width_) {
      case 1:
        val_t = t[s_t].get_fixed_byte(i);
        break;
      case 2:
        val_t = t[s_t].get_fixed_word(i);
        break;
      case 4:
        val_t = t[s_t].get_fixed_double(i);
        break;
      case 8:
        val_t = t[s_t].get_fixed_quad(i);
        break;
      default:
        assert(false);
        break;
      }

      for (const auto& s_r : rewrite_sse_out_) {
        if (s_t != s_r && !relax_reg_) {
          continue;
        }

        uint64_t val_r = 0;
        switch (sse_width_) {
        case 1:
          val_r = r[s_r].get_fixed_byte(i);
          break;
        case 2:
          val_r = r[s_r].get_fixed_word(i);
          break;
        case 4:
          val_r = r[s_r].get_fixed_double(i);
          break;
        case 8:
          val_r = r[s_r].get_fixed_quad(i);
          break;
        default:
          assert(false);
          break;
        }

        const auto eval = evaluate_distance(val_t, val_r) + ((s_t == s_r) ? 0 : misalign_penalty_);
        delta = min(delta, eval);
      }
      cost += delta;
    }
  }

  return cost;
}

Cost CostFunction::mem_error(const Memory& t, const Memory& r) const {
  Cost cost = 0;

  for (auto i = t.defined_begin(), ie = t.defined_end(); i != ie; ++i) {
    if (relax_mem_) {
      Cost delta = max_error_cost;
      for (auto j = r.defined_begin(), je = r.defined_end(); j != je; ++j) {
        const auto eval = evaluate_distance(t[*i], r[*j]) + (*i == *j ? 0 : misalign_penalty_);
        delta = min(delta, eval);
      }
      cost += delta;
    } else {
      cost += r.is_defined(*i) ? evaluate_distance(t[*i], r[*i]) : max_error_cost;
    }
  }

  return cost;
}

Cost CostFunction::rflags_error(const RFlags& t, const RFlags& r) const {
  Cost cost = 0;

  auto flags = vector<Eflags> { eflags_cf, eflags_pf, eflags_af, eflags_zf, eflags_of, eflags_sf };

  for (auto flag : flags) {
    if (live_out_.contains(flag)) {
      size_t i = flag.index();
      cost += (t.is_set(i) ^ r.is_set(i));
    }
  }

  return cost;
}

Cost CostFunction::assembled_size_cost(const Cfg& cfg) const {

  x64asm::Assembler assm;
  x64asm::Function fxn;

  const auto& code = cfg.get_code();

  assm.start(fxn);

  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {

    if (cfg.is_exit(*b)) {
      continue;
    }

    const auto begin = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = 0, ie = begin + cfg.num_instrs(*b); i < ie; ++i) {
      const auto& instr = code[i];
      if (!instr.is_nop() && !instr.is_ret()) {
        assm.assemble(instr);
      }
    }
  }

  assm.finish();

  uint64_t size = fxn.size();
  if (size <= max_size_) {
    return 0;
  } else {
    return (Cost)((size - max_size_) * size_incr_penalty_ + size_starting_penalty_);
  }

}

Cost CostFunction::evaluate_distance(uint64_t x, uint64_t y) const {
  switch (distance_) {
  case Distance::HAMMING:
    return hamming_distance(x, y);
  case Distance::ULP:
    return ulp_distance(x, y);
  case Distance::EXTENSION:
    return extension_distance(x, y);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::ulp_distance(uint64_t x, uint64_t y) const {
  auto t = *((int64_t*)&x);
  t = t < 0 ? numeric_limits<int64_t>::min() - t : t;

  auto r = *((int64_t*)&y);
  r = r < 0 ? numeric_limits<int64_t>::min() - r : r;

  uint64_t ulp = t >= r ? t - r : r - t;
  ulp = ulp < min_ulp_ ? 0 : ulp - min_ulp_;

  return ulp > max_error_cost ? max_error_cost : ulp;
}

Cost CostFunction::extension_distance(uint64_t x, uint64_t y) const {
  Cost res = 0;

  // Add user-defined implementation here ...

  // Invariant 1: Return value should not exceed max_error_cost

  return res;
}

Cost CostFunction::evaluate_performance(const Cfg& cfg, const Cost max) const {
  switch (pterm_) {
  case PerformanceTerm::SIZE:
    return size_performance(cfg);
  case PerformanceTerm::LATENCY:
    return latency_performance(cfg);
  case PerformanceTerm::EXTENSION:
    return extension_performance(cfg);
  default:
    assert(false);
    return 0;
  }
}

Cost CostFunction::size_performance(const Cfg& cfg) const {
  Cost size = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      if (!code[i].is_nop()) {
        size++;
      }
    }
  }

  return size;
}

Cost CostFunction::latency_performance(const Cfg& cfg) const {
  Cost latency = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    Cost block_latency = 0;
    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      if (!code[i].is_nop()) {
        block_latency += latencies_[code[i].get_opcode()];
      }
    }

    latency += block_latency * pow(nesting_penalty_, cfg.nesting_depth(*b));
  }

  return latency;
}

Cost CostFunction::extension_performance(const Cfg& cfg) const {
  Cost res = 0;

  // Add user-defined implementation here ...

  // Invariant: Return value should not exceed max_performance_cost
  assert(res <= max_performance_cost);

  return res;
}

} // namespace stoke
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/global.hpp"
#include "libbirch/Span.hpp"
#include "libbirch/Index.hpp"
#include "libbirch/Range.hpp"
#include "libbirch/View.hpp"
#include "libbirch/Eigen.hpp"

#include <cstddef>

namespace bi {
/**
 * Empty frame.
 *
 * @ingroup libbirch
 *
 * @see NonemptyFrame
 */
struct EmptyFrame {
  EmptyFrame() {
    //
  }

  /**
   * Special constructor for Eigen integration where all matrices and vectors
   * are treated as matrices, with row and column counts. If this constructor,
   * is reached, it means the array is a vector, and @p length should be one
   * (and is checked for this).
   */
  EmptyFrame(const Eigen::Index cols) {
    assert(cols == 1);
  }

  EmptyFrame operator()(const EmptyView& o) const {
    return EmptyFrame();
  }

  bool conforms(const EmptyFrame& o) const {
    return true;
  }

  template<class Frame1>
  bool conforms(const Frame1& o) const {
    return false;
  }

  bool conforms(const Eigen::Index rows, const Eigen::Index cols) {
    return false;
  }

  bool conforms(const Eigen::Index rows) {
    return false;
  }

  void resize(const EmptyFrame& o) {
    //
  }

  template<class T1>
  void resize(T1* in) {
    //
  }

  void resize(const Eigen::Index cols) {
    // special case for vector represented as N x 1 matrix in Eigen.
    assert(cols == 1);
  }

  int64_t offset(const int64_t n) const {
    return 0;
  }

  int64_t length(const int i) const {
    assert(false);
    return 0;
  }

  int64_t stride(const int i) const {
    assert(false);
    return 0;
  }

  template<class T1>
  void lengths(T1* out) const {
    //
  }

  template<class T1>
  void strides(T1* out) const {
    //
  }

  static constexpr int count() {
    return 0;
  }

  static constexpr int64_t size() {
    return 1;
  }

  static constexpr int64_t volume() {
    return 1;
  }

  static constexpr int64_t block() {
    return 1;
  }

  template<class View>
  int64_t serial(const View& o) const {
    return 0;
  }

  bool contiguous() const {
    return true;
  }

  bool operator==(const EmptyFrame& o) const {
    return true;
  }

  template<class Frame1>
  bool operator==(const Frame1& o) const {
    return false;
  }

  template<class Frame1>
  bool operator!=(const Frame1& o) const {
    return !operator==(o);
  }

  EmptyFrame& operator*=(const int64_t n) {
    return *this;
  }

  EmptyFrame operator*(const int64_t n) const {
    EmptyFrame result(*this);
    result *= n;
    return result;
  }
};

/**
 * Nonempty frame.
 *
 * @ingroup libbirch
 *
 * @tparam Tail Frame type.
 * @tparam Head Span type.
 *
 * A frame describes the `D` dimensions of an array. It consists of a
 * @em head span describing the first dimension, and a tail @em tail frame
 * describing the remaining `D - 1` dimensions, recursively. The tail frame
 * is EmptyFrame for the last dimension.
 */
template<class Head, class Tail>
struct NonemptyFrame {
  /**
   * Head type.
   */
  typedef Head head_type;

  /**
   * Tail type.
   */
  typedef Tail tail_type;

  /**
   * Default constructor (for zero-size frame).
   */
  NonemptyFrame() {
    //
  }

  /*
   * Special constructor for Eigen integration where all matrices and vectors
   * are treated as matrices, with row and column counts.
   */
  NonemptyFrame(const Eigen::Index rows, const Eigen::Index cols = 1) :
      head(rows, cols),
      tail(cols) {
    //
  }

  /**
   * Generic constructor.
   */
  template<class Head1, class Tail1>
  NonemptyFrame(const Head1 head, const Tail1 tail) :
      head(head),
      tail(tail) {
    //
  }

  /**
   * Generic copy constructor.
   */
  template<class Head1, class Tail1>
  NonemptyFrame(const NonemptyFrame<Head1,Tail1>& o) :
      head(o.head),
      tail(o.tail) {
    //
  }

  /**
   * View operator.
   */
  template<int64_t offset_value1, int64_t length_value1, class Tail1>
  auto operator()(
      const NonemptyView<Range<offset_value1,length_value1>,Tail1>& o) const {
    /* pre-conditions */
    assert(o.head.offset >= 0);
    assert(o.head.offset + o.head.length <= head.length);

    return NonemptyFrame<decltype(head(o.head)),decltype(tail(o.tail))>(
        head(o.head), tail(o.tail));
  }

  /**
   * View operator.
   */
  template<int64_t offset_value1, class Tail1>
  auto operator()(const NonemptyView<Index<offset_value1>,Tail1>& o) const {
    /* pre-condition */
    assert(o.head.offset >= 0 && o.head.offset < head.length);

    return o.head.offset * head.stride + tail(o.tail);
  }

  /**
   * Does this frame conform to another? Two frames conform if their spans
   * conform.
   */
  bool conforms(const EmptyFrame& o) const {
    return false;
  }
  template<class Frame1>
  bool conforms(const Frame1& o) const {
    return head.conforms(o.head) && tail.conforms(o.tail);
  }
  bool conforms(const Eigen::Index rows, const Eigen::Index cols) {
    return head.conforms(rows) && (tail.conforms(cols) ||
        (std::is_same<Tail,EmptyFrame>::value && cols == 1));
  }
  bool conforms(const Eigen::Index rows) {
    return head.conforms(rows);
  }

  /**
   * Resize this frame to conform to another.
   */
  template<class Frame1>
  void resize(const Frame1& o) {
    tail.resize(o.tail);
    head.length = o.head.length;
    head.stride = tail.volume();
  }
  template<class T1>
  void resize(T1* in) {
    tail.resize(in + 1);
    head.length = *in;
    head.stride = tail.volume();
  }
  void resize(const Eigen::Index rows, const Eigen::Index cols) {
    tail.resize(cols);
    head.length = rows;
    head.stride = tail.volume();
  }
  void resize(const Eigen::Index rows) {
    head.length = rows;
    head.stride = tail.volume();
  }

  /**
   * Compute the offset to the @p n th element in storage order.
   *
   * @param n Element number.
   */
  int64_t offset(const int64_t n) const {
    int64_t s = tail.size();
    if (s > 0) {
      int64_t q = n / s;
      int64_t r = n % s;
      return q * head.stride + tail.offset(r);
    } else {
      return 0;
    }
  }

  /**
   * @name Getters
   */
  //@{
  /**
   * Get the length of the @p i th dimension.
   */
  int64_t length(const int i) const {
    /* pre-condition */
    assert(i >= 0 && i < count());

    if (i == 0) {
      return head.length;
    } else {
      return tail.length(i - 1);
    }
  }

  /**
   * Get the stride of the @p i th dimension.
   */
  int64_t stride(const int i) const {
    /* pre-condition */
    assert(i >= 0 && i < count());

    if (i == 0) {
      return head.stride;
    } else {
      return tail.stride(i - 1);
    }
  }

  /**
   * Get lengths.
   *
   * @tparam T1 Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class T1>
  void lengths(T1* out) const {
    *out = head.length;
    tail.lengths(out + 1);
  }

  /**
   * Get strides.
   *
   * @tparam T1 Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class T1>
  void strides(T1* out) const {
    *out = head.stride;
    tail.strides(out + 1);
  }
  //@}

  /**
   * @name Reductions
   */
  //@{
  /**
   * Number of dimensions.
   */
  static constexpr int count() {
    return 1 + Tail::count();
  }

  /**
   * Product of all lengths.
   */
  int64_t size() const {
    return head.length*tail.size();
  }

  /**
   * Product of all strides.
   */
  int64_t volume() const {
    return head.length*head.stride;
  }

  /**
   * Size of contiguous blocks.
   */
  int64_t block() const {
    int64_t block = tail.block();
    return head.stride == block ? head.length*head.stride : block;
  }

  /**
   * Serial offset for a view.
   */
  template<class View>
  int64_t serial(const View& o) const {
    assert(o.head.offset >= 0);
    return o.head.offset * head.stride + tail.serial(o.tail);
  }

  /**
   * Are all elements stored contiguously in memory?
   */
  bool contiguous() const {
    return volume() == size();
  }
  //@}

  /**
   * Equality operator.
   */
  template<class Head1, class Tail1>
  bool operator==(const NonemptyFrame<Head1,Tail1>& o) const {
    return head == o.head && tail == o.tail;
  }

  /**
   * Equality operator.
   */
  bool operator==(const EmptyFrame& o) const {
    return false;
  }

  /**
   * Unequality operator.
   */
  template<class Frame1>
  bool operator!=(const Frame1& o) const {
    return !(*this == o);
  }

  /**
   * Head.
   */
  Head head;

  /**
   * Tail
   */
  Tail tail;
};

/**
 * Default frame for `D` dimensions.
 */
template<int D>
struct DefaultFrame {
  typedef NonemptyFrame<Span<>,typename DefaultFrame<D - 1>::type> type;
};
template<>
struct DefaultFrame<0> {
  typedef EmptyFrame type;
};
}
<commit_msg>Fixed views of frames with index followed by range.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/global.hpp"
#include "libbirch/Span.hpp"
#include "libbirch/Index.hpp"
#include "libbirch/Range.hpp"
#include "libbirch/View.hpp"
#include "libbirch/Eigen.hpp"

#include <cstddef>

namespace bi {
/**
 * Empty frame.
 *
 * @ingroup libbirch
 *
 * @see NonemptyFrame
 */
struct EmptyFrame {
  EmptyFrame() {
    //
  }

  /**
   * Special constructor for Eigen integration where all matrices and vectors
   * are treated as matrices, with row and column counts. If this constructor,
   * is reached, it means the array is a vector, and @p length should be one
   * (and is checked for this).
   */
  EmptyFrame(const Eigen::Index cols) {
    assert(cols == 1);
  }

  EmptyFrame operator()(const EmptyView& o) const {
    return EmptyFrame();
  }

  bool conforms(const EmptyFrame& o) const {
    return true;
  }

  template<class Frame1>
  bool conforms(const Frame1& o) const {
    return false;
  }

  bool conforms(const Eigen::Index rows, const Eigen::Index cols) {
    return false;
  }

  bool conforms(const Eigen::Index rows) {
    return false;
  }

  void resize(const EmptyFrame& o) {
    //
  }

  template<class T1>
  void resize(T1* in) {
    //
  }

  void resize(const Eigen::Index cols) {
    // special case for vector represented as N x 1 matrix in Eigen.
    assert(cols == 1);
  }

  int64_t offset(const int64_t n) const {
    return 0;
  }

  int64_t length(const int i) const {
    assert(false);
    return 0;
  }

  int64_t stride(const int i) const {
    assert(false);
    return 0;
  }

  template<class T1>
  void lengths(T1* out) const {
    //
  }

  template<class T1>
  void strides(T1* out) const {
    //
  }

  static constexpr int count() {
    return 0;
  }

  static constexpr int64_t size() {
    return 1;
  }

  static constexpr int64_t volume() {
    return 1;
  }

  static constexpr int64_t block() {
    return 1;
  }

  template<class View>
  int64_t serial(const View& o) const {
    return 0;
  }

  bool contiguous() const {
    return true;
  }

  bool operator==(const EmptyFrame& o) const {
    return true;
  }

  template<class Frame1>
  bool operator==(const Frame1& o) const {
    return false;
  }

  template<class Frame1>
  bool operator!=(const Frame1& o) const {
    return !operator==(o);
  }

  EmptyFrame& operator*=(const int64_t n) {
    return *this;
  }

  EmptyFrame operator*(const int64_t n) const {
    EmptyFrame result(*this);
    result *= n;
    return result;
  }
};

/**
 * Nonempty frame.
 *
 * @ingroup libbirch
 *
 * @tparam Tail Frame type.
 * @tparam Head Span type.
 *
 * A frame describes the `D` dimensions of an array. It consists of a
 * @em head span describing the first dimension, and a tail @em tail frame
 * describing the remaining `D - 1` dimensions, recursively. The tail frame
 * is EmptyFrame for the last dimension.
 */
template<class Head, class Tail>
struct NonemptyFrame {
  /**
   * Head type.
   */
  typedef Head head_type;

  /**
   * Tail type.
   */
  typedef Tail tail_type;

  /**
   * Default constructor (for zero-size frame).
   */
  NonemptyFrame() {
    //
  }

  /*
   * Special constructor for Eigen integration where all matrices and vectors
   * are treated as matrices, with row and column counts.
   */
  NonemptyFrame(const Eigen::Index rows, const Eigen::Index cols = 1) :
      head(rows, cols),
      tail(cols) {
    //
  }

  /**
   * Generic constructor.
   */
  template<class Head1, class Tail1>
  NonemptyFrame(const Head1 head, const Tail1 tail) :
      head(head),
      tail(tail) {
    //
  }

  /**
   * Generic copy constructor.
   */
  template<class Head1, class Tail1>
  NonemptyFrame(const NonemptyFrame<Head1,Tail1>& o) :
      head(o.head),
      tail(o.tail) {
    //
  }

  /**
   * View operator.
   */
  template<int64_t offset_value1, int64_t length_value1, class Tail1>
  auto operator()(
      const NonemptyView<Range<offset_value1,length_value1>,Tail1>& o) const {
    /* pre-conditions */
    assert(o.head.offset >= 0);
    assert(o.head.offset + o.head.length <= head.length);

    return NonemptyFrame<decltype(head(o.head)),decltype(tail(o.tail))>(
        head(o.head), tail(o.tail));
  }

  /**
   * View operator.
   */
  template<int64_t offset_value1, class Tail1>
  auto operator()(const NonemptyView<Index<offset_value1>,Tail1>& o) const {
    /* pre-condition */
    assert(o.head.offset >= 0 && o.head.offset < head.length);

    return tail(o.tail);
  }

  /**
   * Does this frame conform to another? Two frames conform if their spans
   * conform.
   */
  bool conforms(const EmptyFrame& o) const {
    return false;
  }
  template<class Frame1>
  bool conforms(const Frame1& o) const {
    return head.conforms(o.head) && tail.conforms(o.tail);
  }
  bool conforms(const Eigen::Index rows, const Eigen::Index cols) {
    return head.conforms(rows) && (tail.conforms(cols) ||
        (std::is_same<Tail,EmptyFrame>::value && cols == 1));
  }
  bool conforms(const Eigen::Index rows) {
    return head.conforms(rows);
  }

  /**
   * Resize this frame to conform to another.
   */
  template<class Frame1>
  void resize(const Frame1& o) {
    tail.resize(o.tail);
    head.length = o.head.length;
    head.stride = tail.volume();
  }
  template<class T1>
  void resize(T1* in) {
    tail.resize(in + 1);
    head.length = *in;
    head.stride = tail.volume();
  }
  void resize(const Eigen::Index rows, const Eigen::Index cols) {
    tail.resize(cols);
    head.length = rows;
    head.stride = tail.volume();
  }
  void resize(const Eigen::Index rows) {
    head.length = rows;
    head.stride = tail.volume();
  }

  /**
   * Compute the offset to the @p n th element in storage order.
   *
   * @param n Element number.
   */
  int64_t offset(const int64_t n) const {
    int64_t s = tail.size();
    if (s > 0) {
      int64_t q = n / s;
      int64_t r = n % s;
      return q * head.stride + tail.offset(r);
    } else {
      return 0;
    }
  }

  /**
   * @name Getters
   */
  //@{
  /**
   * Get the length of the @p i th dimension.
   */
  int64_t length(const int i) const {
    /* pre-condition */
    assert(i >= 0 && i < count());

    if (i == 0) {
      return head.length;
    } else {
      return tail.length(i - 1);
    }
  }

  /**
   * Get the stride of the @p i th dimension.
   */
  int64_t stride(const int i) const {
    /* pre-condition */
    assert(i >= 0 && i < count());

    if (i == 0) {
      return head.stride;
    } else {
      return tail.stride(i - 1);
    }
  }

  /**
   * Get lengths.
   *
   * @tparam T1 Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class T1>
  void lengths(T1* out) const {
    *out = head.length;
    tail.lengths(out + 1);
  }

  /**
   * Get strides.
   *
   * @tparam T1 Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class T1>
  void strides(T1* out) const {
    *out = head.stride;
    tail.strides(out + 1);
  }
  //@}

  /**
   * @name Reductions
   */
  //@{
  /**
   * Number of dimensions.
   */
  static constexpr int count() {
    return 1 + Tail::count();
  }

  /**
   * Product of all lengths.
   */
  int64_t size() const {
    return head.length*tail.size();
  }

  /**
   * Product of all strides.
   */
  int64_t volume() const {
    return head.length*head.stride;
  }

  /**
   * Size of contiguous blocks.
   */
  int64_t block() const {
    int64_t block = tail.block();
    return head.stride == block ? head.length*head.stride : block;
  }

  /**
   * Serial offset for a view.
   */
  template<class View>
  int64_t serial(const View& o) const {
    assert(o.head.offset >= 0);
    return o.head.offset * head.stride + tail.serial(o.tail);
  }

  /**
   * Are all elements stored contiguously in memory?
   */
  bool contiguous() const {
    return volume() == size();
  }
  //@}

  /**
   * Equality operator.
   */
  template<class Head1, class Tail1>
  bool operator==(const NonemptyFrame<Head1,Tail1>& o) const {
    return head == o.head && tail == o.tail;
  }

  /**
   * Equality operator.
   */
  bool operator==(const EmptyFrame& o) const {
    return false;
  }

  /**
   * Unequality operator.
   */
  template<class Frame1>
  bool operator!=(const Frame1& o) const {
    return !(*this == o);
  }

  /**
   * Head.
   */
  Head head;

  /**
   * Tail
   */
  Tail tail;
};

/**
 * Default frame for `D` dimensions.
 */
template<int D>
struct DefaultFrame {
  typedef NonemptyFrame<Span<>,typename DefaultFrame<D - 1>::type> type;
};
template<>
struct DefaultFrame<0> {
  typedef EmptyFrame type;
};
}
<|endoftext|>


<commit_before>#include "custom-pwm/custom-pwm.h"

void CustomPwm::init(void) {
  pinMode(_pin, OUTPUT);
  analogWriteResolution(_pin, _resolution);
}

void CustomPwm::out(uint32_t value) {
  analogWrite(_pin, value, _frequency); // 3000/4095 = ~73% duty cycle at 1kHz
}

uint16_t CustomPwm::MaxFreq(void){
  return analogWriteMaxFrequency(_pin);
}
<commit_msg>correcting<commit_after>#include "custom-pwm.h"

void CustomPwm::init(void) {
  pinMode(_pin, OUTPUT);
  analogWriteResolution(_pin, _resolution);
}

void CustomPwm::out(uint32_t value) {
  analogWrite(_pin, value, _frequency); // 3000/4095 = ~73% duty cycle at 1kHz
}

uint16_t CustomPwm::MaxFreq(void){
  return analogWriteMaxFrequency(_pin);
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

// Client implementation for Flight integration testing. Loads
// RecordBatches from the given JSON file and uploads them to the
// Flight server, which stores the data and schema in memory. The
// client then requests the data from the server and compares it to
// the data originally uploaded.

#include <iostream>
#include <memory>
#include <string>

#include <gflags/gflags.h>

#include "arrow/io/file.h"
#include "arrow/io/test_common.h"
#include "arrow/ipc/dictionary.h"
#include "arrow/ipc/writer.h"
#include "arrow/record_batch.h"
#include "arrow/table.h"
#include "arrow/testing/extension_type.h"
#include "arrow/testing/gtest_util.h"
#include "arrow/testing/json_integration.h"
#include "arrow/util/logging.h"

#include "arrow/flight/api.h"
#include "arrow/flight/test_integration.h"
#include "arrow/flight/test_util.h"

DEFINE_string(host, "localhost", "Server port to connect to");
DEFINE_int32(port, 31337, "Server port to connect to");
DEFINE_string(path, "", "Resource path to request");
DEFINE_string(scenario, "", "Integration test scenario to run");

namespace arrow {
namespace flight {

/// \brief Helper to read all batches from a JsonReader
Status ReadBatches(std::unique_ptr<testing::IntegrationJsonReader>& reader,
                   std::vector<std::shared_ptr<RecordBatch>>* chunks) {
  std::shared_ptr<RecordBatch> chunk;
  for (int i = 0; i < reader->num_record_batches(); i++) {
    RETURN_NOT_OK(reader->ReadRecordBatch(i, &chunk));
    RETURN_NOT_OK(chunk->ValidateFull());
    chunks->push_back(chunk);
  }
  return Status::OK();
}

/// \brief Upload the a list of batches to a Flight server, validating
/// the application metadata on the side.
Status UploadBatchesToFlight(const std::vector<std::shared_ptr<RecordBatch>>& chunks,
                             FlightStreamWriter& writer,
                             FlightMetadataReader& metadata_reader) {
  int counter = 0;
  for (const auto& chunk : chunks) {
    std::shared_ptr<Buffer> metadata = Buffer::FromString(std::to_string(counter));
    RETURN_NOT_OK(writer.WriteWithMetadata(*chunk, metadata));
    // Wait for the server to ack the result
    std::shared_ptr<Buffer> ack_metadata;
    RETURN_NOT_OK(metadata_reader.ReadMetadata(&ack_metadata));
    if (!ack_metadata) {
      return Status::Invalid("Expected metadata value: ", metadata->ToString(),
                             " but got nothing.");
    } else if (!ack_metadata->Equals(*metadata)) {
      return Status::Invalid("Expected metadata value: ", metadata->ToString(),
                             " but got: ", ack_metadata->ToString());
    }
    counter++;
  }
  return writer.Close();
}

/// \brief Retrieve the given Flight and compare to the original expected batches.
Status ConsumeFlightLocation(
    const Location& location, const Ticket& ticket,
    const std::vector<std::shared_ptr<RecordBatch>>& retrieved_data) {
  std::unique_ptr<FlightClient> read_client;
  RETURN_NOT_OK(FlightClient::Connect(location, &read_client));

  std::unique_ptr<FlightStreamReader> stream;
  RETURN_NOT_OK(read_client->DoGet(ticket, &stream));

  int counter = 0;
  const int expected = static_cast<int>(retrieved_data.size());
  for (const auto& original_batch : retrieved_data) {
    FlightStreamChunk chunk;
    RETURN_NOT_OK(stream->Next(&chunk));
    if (chunk.data == nullptr) {
      return Status::Invalid("Got fewer batches than expected, received so far: ",
                             counter, " expected ", expected);
    }

    if (!original_batch->Equals(*chunk.data)) {
      return Status::Invalid("Batch ", counter, " does not match");
    }

    const auto st = chunk.data->ValidateFull();
    if (!st.ok()) {
      return Status::Invalid("Batch ", counter, " is not valid: ", st.ToString());
    }

    if (std::to_string(counter) != chunk.app_metadata->ToString()) {
      return Status::Invalid("Expected metadata value: " + std::to_string(counter) +
                             " but got: " + chunk.app_metadata->ToString());
    }
    counter++;
  }

  FlightStreamChunk chunk;
  RETURN_NOT_OK(stream->Next(&chunk));
  if (chunk.data != nullptr) {
    return Status::Invalid("Got more batches than the expected ", expected);
  }

  return Status::OK();
}

class IntegrationTestScenario : public flight::Scenario {
 public:
  Status MakeServer(std::unique_ptr<FlightServerBase>* server,
                    FlightServerOptions* options) override {
    ARROW_UNUSED(server);
    ARROW_UNUSED(options);
    return Status::NotImplemented("Not implemented, see test_integration_server.cc");
  }

  Status MakeClient(FlightClientOptions* options) override {
    ARROW_UNUSED(options);
    return Status::OK();
  }

  Status RunClient(std::unique_ptr<FlightClient> client) override {
    // Make sure the required extension types are registered.
    ExtensionTypeGuard uuid_ext_guard(uuid());
    ExtensionTypeGuard dict_ext_guard(dict_extension_type());

    FlightDescriptor descr{FlightDescriptor::PATH, "", {FLAGS_path}};

    // 1. Put the data to the server.
    std::unique_ptr<testing::IntegrationJsonReader> reader;
    std::cout << "Opening JSON file '" << FLAGS_path << "'" << std::endl;
    auto in_file = *io::ReadableFile::Open(FLAGS_path);
    ABORT_NOT_OK(
        testing::IntegrationJsonReader::Open(default_memory_pool(), in_file, &reader));

    std::shared_ptr<Schema> original_schema = reader->schema();
    std::vector<std::shared_ptr<RecordBatch>> original_data;
    ABORT_NOT_OK(ReadBatches(reader, &original_data));

    std::unique_ptr<FlightStreamWriter> write_stream;
    std::unique_ptr<FlightMetadataReader> metadata_reader;
    ABORT_NOT_OK(client->DoPut(descr, original_schema, &write_stream, &metadata_reader));
    ABORT_NOT_OK(UploadBatchesToFlight(original_data, *write_stream, *metadata_reader));

    // 2. Get the ticket for the data.
    std::unique_ptr<FlightInfo> info;
    ABORT_NOT_OK(client->GetFlightInfo(descr, &info));

    std::shared_ptr<Schema> schema;
    ipc::DictionaryMemo dict_memo;
    ABORT_NOT_OK(info->GetSchema(&dict_memo, &schema));

    if (info->endpoints().size() == 0) {
      std::cerr << "No endpoints returned from Flight server." << std::endl;
      return Status::IOError("No endpoints returned from Flight server.");
    }

    for (const FlightEndpoint& endpoint : info->endpoints()) {
      const auto& ticket = endpoint.ticket;

      auto locations = endpoint.locations;
      if (locations.size() == 0) {
        return Status::IOError("No locations returned from Flight server.");
      }

      for (const auto& location : locations) {
        std::cout << "Verifying location " << location.ToString() << std::endl;
        // 3. Stream data from the server, comparing individual batches.
        ABORT_NOT_OK(ConsumeFlightLocation(location, ticket, original_data));
      }
    }
    return Status::OK();
  }
};

}  // namespace flight
}  // namespace arrow

int main(int argc, char** argv) {
  arrow::util::ArrowLog::InstallFailureSignalHandler();

  gflags::SetUsageMessage("Integration testing client for Flight.");
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::shared_ptr<arrow::flight::Scenario> scenario;
  if (!FLAGS_scenario.empty()) {
    ARROW_CHECK_OK(arrow::flight::GetScenario(FLAGS_scenario, &scenario));
  } else {
    scenario = std::make_shared<arrow::flight::IntegrationTestScenario>();
  }

  arrow::flight::FlightClientOptions options =
      arrow::flight::FlightClientOptions::Defaults();
  std::unique_ptr<arrow::flight::FlightClient> client;

  ABORT_NOT_OK(scenario->MakeClient(&options));

  arrow::flight::Location location;
  ABORT_NOT_OK(arrow::flight::Location::ForGrpcTcp(FLAGS_host, FLAGS_port, &location));
  ABORT_NOT_OK(arrow::flight::FlightClient::Connect(location, options, &client));
  ABORT_NOT_OK(scenario->RunClient(std::move(client)));

  arrow::util::ArrowLog::UninstallSignalAction();
  return 0;
}
<commit_msg>ARROW-11908: [C++] Work around flaky integration by retrying<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

// Client implementation for Flight integration testing. Loads
// RecordBatches from the given JSON file and uploads them to the
// Flight server, which stores the data and schema in memory. The
// client then requests the data from the server and compares it to
// the data originally uploaded.

#include <chrono>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

#include <gflags/gflags.h>

#include "arrow/io/file.h"
#include "arrow/io/test_common.h"
#include "arrow/ipc/dictionary.h"
#include "arrow/ipc/writer.h"
#include "arrow/record_batch.h"
#include "arrow/table.h"
#include "arrow/testing/extension_type.h"
#include "arrow/testing/gtest_util.h"
#include "arrow/testing/json_integration.h"
#include "arrow/util/logging.h"

#include "arrow/flight/api.h"
#include "arrow/flight/test_integration.h"
#include "arrow/flight/test_util.h"

DEFINE_string(host, "localhost", "Server port to connect to");
DEFINE_int32(port, 31337, "Server port to connect to");
DEFINE_string(path, "", "Resource path to request");
DEFINE_string(scenario, "", "Integration test scenario to run");

namespace arrow {
namespace flight {

/// \brief Helper to read all batches from a JsonReader
Status ReadBatches(std::unique_ptr<testing::IntegrationJsonReader>& reader,
                   std::vector<std::shared_ptr<RecordBatch>>* chunks) {
  std::shared_ptr<RecordBatch> chunk;
  for (int i = 0; i < reader->num_record_batches(); i++) {
    RETURN_NOT_OK(reader->ReadRecordBatch(i, &chunk));
    RETURN_NOT_OK(chunk->ValidateFull());
    chunks->push_back(chunk);
  }
  return Status::OK();
}

/// \brief Upload the a list of batches to a Flight server, validating
/// the application metadata on the side.
Status UploadBatchesToFlight(const std::vector<std::shared_ptr<RecordBatch>>& chunks,
                             FlightStreamWriter& writer,
                             FlightMetadataReader& metadata_reader) {
  int counter = 0;
  for (const auto& chunk : chunks) {
    std::shared_ptr<Buffer> metadata = Buffer::FromString(std::to_string(counter));
    RETURN_NOT_OK(writer.WriteWithMetadata(*chunk, metadata));
    // Wait for the server to ack the result
    std::shared_ptr<Buffer> ack_metadata;
    RETURN_NOT_OK(metadata_reader.ReadMetadata(&ack_metadata));
    if (!ack_metadata) {
      return Status::Invalid("Expected metadata value: ", metadata->ToString(),
                             " but got nothing.");
    } else if (!ack_metadata->Equals(*metadata)) {
      return Status::Invalid("Expected metadata value: ", metadata->ToString(),
                             " but got: ", ack_metadata->ToString());
    }
    counter++;
  }
  return writer.Close();
}

/// \brief Retrieve the given Flight and compare to the original expected batches.
Status ConsumeFlightLocation(
    const Location& location, const Ticket& ticket,
    const std::vector<std::shared_ptr<RecordBatch>>& retrieved_data) {
  std::unique_ptr<FlightClient> read_client;
  RETURN_NOT_OK(FlightClient::Connect(location, &read_client));

  std::unique_ptr<FlightStreamReader> stream;
  RETURN_NOT_OK(read_client->DoGet(ticket, &stream));

  int counter = 0;
  const int expected = static_cast<int>(retrieved_data.size());
  for (const auto& original_batch : retrieved_data) {
    FlightStreamChunk chunk;
    RETURN_NOT_OK(stream->Next(&chunk));
    if (chunk.data == nullptr) {
      return Status::Invalid("Got fewer batches than expected, received so far: ",
                             counter, " expected ", expected);
    }

    if (!original_batch->Equals(*chunk.data)) {
      return Status::Invalid("Batch ", counter, " does not match");
    }

    const auto st = chunk.data->ValidateFull();
    if (!st.ok()) {
      return Status::Invalid("Batch ", counter, " is not valid: ", st.ToString());
    }

    if (std::to_string(counter) != chunk.app_metadata->ToString()) {
      return Status::Invalid("Expected metadata value: " + std::to_string(counter) +
                             " but got: " + chunk.app_metadata->ToString());
    }
    counter++;
  }

  FlightStreamChunk chunk;
  RETURN_NOT_OK(stream->Next(&chunk));
  if (chunk.data != nullptr) {
    return Status::Invalid("Got more batches than the expected ", expected);
  }

  return Status::OK();
}

class IntegrationTestScenario : public flight::Scenario {
 public:
  Status MakeServer(std::unique_ptr<FlightServerBase>* server,
                    FlightServerOptions* options) override {
    ARROW_UNUSED(server);
    ARROW_UNUSED(options);
    return Status::NotImplemented("Not implemented, see test_integration_server.cc");
  }

  Status MakeClient(FlightClientOptions* options) override {
    ARROW_UNUSED(options);
    return Status::OK();
  }

  Status RunClient(std::unique_ptr<FlightClient> client) override {
    // Make sure the required extension types are registered.
    ExtensionTypeGuard uuid_ext_guard(uuid());
    ExtensionTypeGuard dict_ext_guard(dict_extension_type());

    FlightDescriptor descr{FlightDescriptor::PATH, "", {FLAGS_path}};

    // 1. Put the data to the server.
    std::unique_ptr<testing::IntegrationJsonReader> reader;
    std::cout << "Opening JSON file '" << FLAGS_path << "'" << std::endl;
    auto in_file = *io::ReadableFile::Open(FLAGS_path);
    ABORT_NOT_OK(
        testing::IntegrationJsonReader::Open(default_memory_pool(), in_file, &reader));

    std::shared_ptr<Schema> original_schema = reader->schema();
    std::vector<std::shared_ptr<RecordBatch>> original_data;
    ABORT_NOT_OK(ReadBatches(reader, &original_data));

    std::unique_ptr<FlightStreamWriter> write_stream;
    std::unique_ptr<FlightMetadataReader> metadata_reader;
    ABORT_NOT_OK(client->DoPut(descr, original_schema, &write_stream, &metadata_reader));
    ABORT_NOT_OK(UploadBatchesToFlight(original_data, *write_stream, *metadata_reader));

    // 2. Get the ticket for the data.
    std::unique_ptr<FlightInfo> info;
    ABORT_NOT_OK(client->GetFlightInfo(descr, &info));

    std::shared_ptr<Schema> schema;
    ipc::DictionaryMemo dict_memo;
    ABORT_NOT_OK(info->GetSchema(&dict_memo, &schema));

    if (info->endpoints().size() == 0) {
      std::cerr << "No endpoints returned from Flight server." << std::endl;
      return Status::IOError("No endpoints returned from Flight server.");
    }

    for (const FlightEndpoint& endpoint : info->endpoints()) {
      const auto& ticket = endpoint.ticket;

      auto locations = endpoint.locations;
      if (locations.size() == 0) {
        return Status::IOError("No locations returned from Flight server.");
      }

      for (const auto& location : locations) {
        std::cout << "Verifying location " << location.ToString() << std::endl;
        // 3. Stream data from the server, comparing individual batches.
        ABORT_NOT_OK(ConsumeFlightLocation(location, ticket, original_data));
      }
    }
    return Status::OK();
  }
};

}  // namespace flight
}  // namespace arrow

constexpr int kRetries = 3;

arrow::Status RunScenario(arrow::flight::Scenario* scenario) {
  auto options = arrow::flight::FlightClientOptions::Defaults();
  std::unique_ptr<arrow::flight::FlightClient> client;

  RETURN_NOT_OK(scenario->MakeClient(&options));
  arrow::flight::Location location;
  RETURN_NOT_OK(arrow::flight::Location::ForGrpcTcp(FLAGS_host, FLAGS_port, &location));
  RETURN_NOT_OK(arrow::flight::FlightClient::Connect(location, options, &client));
  return scenario->RunClient(std::move(client));
}

int main(int argc, char** argv) {
  arrow::util::ArrowLog::InstallFailureSignalHandler();

  gflags::SetUsageMessage("Integration testing client for Flight.");
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::shared_ptr<arrow::flight::Scenario> scenario;
  if (!FLAGS_scenario.empty()) {
    ARROW_CHECK_OK(arrow::flight::GetScenario(FLAGS_scenario, &scenario));
  } else {
    scenario = std::make_shared<arrow::flight::IntegrationTestScenario>();
  }

  // ARROW-11908: retry a few times in case a client is slow to bring up the server
  auto status = arrow::Status::OK();
  for (int i = 0; i < kRetries; i++) {
    status = RunScenario(scenario.get());
    if (status.ok()) break;
    // Failed, wait a bit and try again
    std::this_thread::sleep_for(std::chrono::milliseconds((i + 1) * 500));
  }
  ABORT_NOT_OK(status);

  arrow::util::ArrowLog::UninstallSignalAction();
  return 0;
}
<|endoftext|>


<commit_before>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/SimpleTextObserver>
#include "TelepathyQt4/simple-text-observer-internal.h"

#include "TelepathyQt4/_gen/simple-text-observer.moc.hpp"
#include "TelepathyQt4/_gen/simple-text-observer-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/ChannelClassSpec>
#include <TelepathyQt4/ChannelClassSpecList>
#include <TelepathyQt4/Contact>
#include <TelepathyQt4/Message>
#include <TelepathyQt4/PendingReady>

namespace Tp
{

uint SimpleTextObserver::Private::numObservers = 0;

SimpleTextObserver::Private::Private(const ClientRegistrarPtr &cr, const AccountPtr &account,
        const QString &contactIdentifier)
    : cr(cr),
      account(account),
      contactIdentifier(contactIdentifier)
{
}

SimpleTextObserver::Private::~Private()
{
    for (QHash<TextChannelPtr, TextChannelWrapper*>::iterator i = channels.begin();
            i != channels.end();) {
        delete i.value();
    }
}

SimpleTextObserver::Private::TextChannelWrapper::TextChannelWrapper(const TextChannelPtr &channel)
    : mChannel(channel)
{
    connect(channel.data(),
            SIGNAL(invalidated(Tp::PendingOperation*)),
            SLOT(onChannelInvalidated()));

    Features features = TextChannel::FeatureMessageQueue | TextChannel::FeatureMessageSentSignal;
    if (!channel->isReady(features)) {
        // The channel factory passed to the Account used by SimpleTextObserver does not contain the
        // neeeded features, request them
        connect(channel->becomeReady(features),
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(onChannelReady()));
    } else {
        onChannelReady();
    }
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelInvalidated()
{
    emit channelInvalidated(mChannel);
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelReady()
{
    connect(mChannel.data(),
            SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
            SLOT(onChannelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
    connect(mChannel.data(),
            SIGNAL(messageReceived(Tp::ReceivedMessage)),
            SLOT(onChannelMessageReceived(Tp::ReceivedMessage)));

    foreach (const ReceivedMessage &message, mChannel->messageQueue()) {
        onChannelMessageReceived(message);
    }
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageSent(
        const Tp::Message &message, Tp::MessageSendingFlags flags,
        const QString &sentMessageToken)
{
    emit channelMessageSent(message, flags, sentMessageToken, mChannel);
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageReceived(
        const Tp::ReceivedMessage &message)
{
    emit channelMessageReceived(message, mChannel);
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account)
{
    return create(account, QString());
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account,
        const ContactPtr &contact)
{
    if (contact) {
        return create(account, contact->id());
    }
    return create(account, QString());
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account,
        const QString &contactIdentifier)
{
    QVariantMap additionalProperties;
    if (!contactIdentifier.isEmpty()) {
        QVariantMap additionalProperties;
        additionalProperties.insert(TP_QT4_IFACE_CHANNEL + QLatin1String(".TargetID"),
                contactIdentifier);
    }
    ChannelClassSpec channelFilter = ChannelClassSpec::textChat(additionalProperties);

    ClientRegistrarPtr cr = ClientRegistrar::create(
            Private::FakeAccountFactory::create(account),
            account->connectionFactory(),
            account->channelFactory(),
            account->contactFactory());

    SimpleTextObserverPtr observer = SimpleTextObserverPtr(
            new SimpleTextObserver(cr, ChannelClassSpecList() << channelFilter,
                account, contactIdentifier));

    QString observerName = QString(QLatin1String("TpQt4STO_%1_%2"))
        .arg(account->dbusConnection().baseService()
            .replace(QLatin1String(":"), QLatin1String("_"))
            .replace(QLatin1String("."), QLatin1String("_")))
        .arg(Private::numObservers++);
    if (!cr->registerClient(observer, observerName, false)) {
        warning() << "Unable to register observer" << observerName;
        return SimpleTextObserverPtr();
    }

    return observer;
}

SimpleTextObserver::SimpleTextObserver(const ClientRegistrarPtr &cr,
        const ChannelClassSpecList &channelFilter,
        const AccountPtr &account, const QString &contactIdentifier)
    : QObject(),
      AbstractClientObserver(channelFilter, true),
      mPriv(new Private(cr, account, contactIdentifier))
{
}

SimpleTextObserver::~SimpleTextObserver()
{
    delete mPriv;
}

void SimpleTextObserver::observeChannels(
        const MethodInvocationContextPtr<> &context,
        const AccountPtr &account,
        const ConnectionPtr &connection,
        const QList<ChannelPtr> &channels,
        const ChannelDispatchOperationPtr &dispatchOperation,
        const QList<ChannelRequestPtr> &requestsSatisfied,
        const ObserverInfo &observerInfo)
{
    if (account != mPriv->account) {
        context->setFinished();
        return;
    }

    foreach (const ChannelPtr &channel, channels) {
        TextChannelPtr textChannel = TextChannelPtr::qObjectCast(channel);
        if (!textChannel) {
            if (channel->channelType() != TP_QT4_IFACE_CHANNEL_TYPE_TEXT) {
                warning() << "Channel received to observe is not of type Text, service confused. "
                    "Ignoring channel";
            } else {
                warning() << "Channel received to observe is not a subclass of TextChannel. "
                    "ChannelFactory set on this observer's account must construct TextChannel "
                    "subclasses for channels of type Text. Ignoring channel";
            }
            continue;
        }

        if (mPriv->channels.contains(textChannel)) {
            // we are already observing this channel
            continue;
        }

        // this shouldn't happen, but in any case
        if (!textChannel->isValid()) {
            warning() << "Channel received to observe is invalid. Ignoring channel";
            continue;
        }

        Private::TextChannelWrapper *wrapper = new Private::TextChannelWrapper(textChannel);
        mPriv->channels.insert(textChannel, wrapper);
        connect(wrapper,
                SIGNAL(channelInvalidated(Tp::TextChannelPtr)),
                SLOT(onChannelInvalidated(Tp::TextChannelPtr)));
        connect(wrapper,
                SIGNAL(channelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)),
                SLOT(onChannelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)));
        connect(wrapper,
                SIGNAL(channelMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)),
                SLOT(onChannelMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)));
    }

    context->setFinished();
}

void SimpleTextObserver::onChannelInvalidated(const TextChannelPtr &textChannel)
{
    delete mPriv->channels.take(textChannel);
}

void SimpleTextObserver::onChannelMessageSent(const Message &message, MessageSendingFlags flags,
        const QString &sentMessageToken, const TextChannelPtr &textChannel)
{
    emit messageSent(message, flags, sentMessageToken, textChannel);
}

void SimpleTextObserver::onChannelMessageReceived(const ReceivedMessage &message,
        const TextChannelPtr &textChannel)
{
    emit messageReceived(message, textChannel);
}

} // Tp
<commit_msg>SimpleTextObserver: Implement accessors for account and contactIdentifier.<commit_after>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/SimpleTextObserver>
#include "TelepathyQt4/simple-text-observer-internal.h"

#include "TelepathyQt4/_gen/simple-text-observer.moc.hpp"
#include "TelepathyQt4/_gen/simple-text-observer-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/ChannelClassSpec>
#include <TelepathyQt4/ChannelClassSpecList>
#include <TelepathyQt4/Contact>
#include <TelepathyQt4/Message>
#include <TelepathyQt4/PendingReady>

namespace Tp
{

uint SimpleTextObserver::Private::numObservers = 0;

SimpleTextObserver::Private::Private(const ClientRegistrarPtr &cr, const AccountPtr &account,
        const QString &contactIdentifier)
    : cr(cr),
      account(account),
      contactIdentifier(contactIdentifier)
{
}

SimpleTextObserver::Private::~Private()
{
    for (QHash<TextChannelPtr, TextChannelWrapper*>::iterator i = channels.begin();
            i != channels.end();) {
        delete i.value();
    }
}

SimpleTextObserver::Private::TextChannelWrapper::TextChannelWrapper(const TextChannelPtr &channel)
    : mChannel(channel)
{
    connect(channel.data(),
            SIGNAL(invalidated(Tp::PendingOperation*)),
            SLOT(onChannelInvalidated()));

    Features features = TextChannel::FeatureMessageQueue | TextChannel::FeatureMessageSentSignal;
    if (!channel->isReady(features)) {
        // The channel factory passed to the Account used by SimpleTextObserver does not contain the
        // neeeded features, request them
        connect(channel->becomeReady(features),
                SIGNAL(finished(Tp::PendingOperation*)),
                SLOT(onChannelReady()));
    } else {
        onChannelReady();
    }
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelInvalidated()
{
    emit channelInvalidated(mChannel);
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelReady()
{
    connect(mChannel.data(),
            SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
            SLOT(onChannelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
    connect(mChannel.data(),
            SIGNAL(messageReceived(Tp::ReceivedMessage)),
            SLOT(onChannelMessageReceived(Tp::ReceivedMessage)));

    foreach (const ReceivedMessage &message, mChannel->messageQueue()) {
        onChannelMessageReceived(message);
    }
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageSent(
        const Tp::Message &message, Tp::MessageSendingFlags flags,
        const QString &sentMessageToken)
{
    emit channelMessageSent(message, flags, sentMessageToken, mChannel);
}

void SimpleTextObserver::Private::TextChannelWrapper::onChannelMessageReceived(
        const Tp::ReceivedMessage &message)
{
    emit channelMessageReceived(message, mChannel);
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account)
{
    return create(account, QString());
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account,
        const ContactPtr &contact)
{
    if (contact) {
        return create(account, contact->id());
    }
    return create(account, QString());
}

SimpleTextObserverPtr SimpleTextObserver::create(const AccountPtr &account,
        const QString &contactIdentifier)
{
    QVariantMap additionalProperties;
    if (!contactIdentifier.isEmpty()) {
        QVariantMap additionalProperties;
        additionalProperties.insert(TP_QT4_IFACE_CHANNEL + QLatin1String(".TargetID"),
                contactIdentifier);
    }
    ChannelClassSpec channelFilter = ChannelClassSpec::textChat(additionalProperties);

    ClientRegistrarPtr cr = ClientRegistrar::create(
            Private::FakeAccountFactory::create(account),
            account->connectionFactory(),
            account->channelFactory(),
            account->contactFactory());

    SimpleTextObserverPtr observer = SimpleTextObserverPtr(
            new SimpleTextObserver(cr, ChannelClassSpecList() << channelFilter,
                account, contactIdentifier));

    QString observerName = QString(QLatin1String("TpQt4STO_%1_%2"))
        .arg(account->dbusConnection().baseService()
            .replace(QLatin1String(":"), QLatin1String("_"))
            .replace(QLatin1String("."), QLatin1String("_")))
        .arg(Private::numObservers++);
    if (!cr->registerClient(observer, observerName, false)) {
        warning() << "Unable to register observer" << observerName;
        return SimpleTextObserverPtr();
    }

    return observer;
}

SimpleTextObserver::SimpleTextObserver(const ClientRegistrarPtr &cr,
        const ChannelClassSpecList &channelFilter,
        const AccountPtr &account, const QString &contactIdentifier)
    : QObject(),
      AbstractClientObserver(channelFilter, true),
      mPriv(new Private(cr, account, contactIdentifier))
{
}

SimpleTextObserver::~SimpleTextObserver()
{
    delete mPriv;
}

AccountPtr SimpleTextObserver::account() const
{
    return mPriv->account;
}

QString SimpleTextObserver::contactIdentifier() const
{
    return mPriv->contactIdentifier;
}

void SimpleTextObserver::observeChannels(
        const MethodInvocationContextPtr<> &context,
        const AccountPtr &account,
        const ConnectionPtr &connection,
        const QList<ChannelPtr> &channels,
        const ChannelDispatchOperationPtr &dispatchOperation,
        const QList<ChannelRequestPtr> &requestsSatisfied,
        const ObserverInfo &observerInfo)
{
    if (account != mPriv->account) {
        context->setFinished();
        return;
    }

    foreach (const ChannelPtr &channel, channels) {
        TextChannelPtr textChannel = TextChannelPtr::qObjectCast(channel);
        if (!textChannel) {
            if (channel->channelType() != TP_QT4_IFACE_CHANNEL_TYPE_TEXT) {
                warning() << "Channel received to observe is not of type Text, service confused. "
                    "Ignoring channel";
            } else {
                warning() << "Channel received to observe is not a subclass of TextChannel. "
                    "ChannelFactory set on this observer's account must construct TextChannel "
                    "subclasses for channels of type Text. Ignoring channel";
            }
            continue;
        }

        if (mPriv->channels.contains(textChannel)) {
            // we are already observing this channel
            continue;
        }

        // this shouldn't happen, but in any case
        if (!textChannel->isValid()) {
            warning() << "Channel received to observe is invalid. Ignoring channel";
            continue;
        }

        Private::TextChannelWrapper *wrapper = new Private::TextChannelWrapper(textChannel);
        mPriv->channels.insert(textChannel, wrapper);
        connect(wrapper,
                SIGNAL(channelInvalidated(Tp::TextChannelPtr)),
                SLOT(onChannelInvalidated(Tp::TextChannelPtr)));
        connect(wrapper,
                SIGNAL(channelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)),
                SLOT(onChannelMessageSent(Tp::Message,Tp::MessageSendingFlags,QString,Tp::TextChannelPtr)));
        connect(wrapper,
                SIGNAL(channelMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)),
                SLOT(onChannelMessageReceived(Tp::ReceivedMessage,Tp::TextChannelPtr)));
    }

    context->setFinished();
}

void SimpleTextObserver::onChannelInvalidated(const TextChannelPtr &textChannel)
{
    delete mPriv->channels.take(textChannel);
}

void SimpleTextObserver::onChannelMessageSent(const Message &message, MessageSendingFlags flags,
        const QString &sentMessageToken, const TextChannelPtr &textChannel)
{
    emit messageSent(message, flags, sentMessageToken, textChannel);
}

void SimpleTextObserver::onChannelMessageReceived(const ReceivedMessage &message,
        const TextChannelPtr &textChannel)
{
    emit messageReceived(message, textChannel);
}

} // Tp
<|endoftext|>


<commit_before>/**
 * File    : D.cpp
 * Author  : Kazune Takahashi
 * Created : 1/12/2019, 9:15:17 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 100000000007;

int N, Q;
ll A[100010];
vector<ll> B;
ll X[100010];
set<ll> S;
map<ll, ll> M;
ll Y[100010];
ll Z[100010];

void flush()
{
  for (auto i = 0; i < Q; i++)
  {
    cout << M[X[i]] << endl;
  }
}

int main()
{
  cin >> N >> Q;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
  }
  for (auto i = 0; i < Q; i++)
  {
    cin >> X[i];
    S.insert(X[i]);
  }
  reverse(A, A + N);
  Y[N + 1] = 0;
  Y[N] = 0;
  Y[N - 1] = A[N - 1];
  Y[N - 2] = A[N - 2];
  for (auto i = N - 3; i >= 0; i--)
  {
    Y[i] = A[i] + Y[i + 2];
  }
  Z[0] = A[0];
  for (auto i = 1; i < N; i++)
  {
    Z[i] = A[i] + Z[i - 1];
  }
  B.push_back(infty);
  for (auto i = 0; i < N; i++)
  {
    B.push_back(A[i]);
  }
  B.push_back(-infty);
  auto it = S.begin();
  for (auto i = N; i >= 0; i--)
  {
    int second = i / 2;
    int first = i - second;
    ll score;
    if (first == 0)
    {
      score = Y[0];
    }
    else if (first == second)
    {
      score = Z[first - 1] + Y[i];
    }
    else
    {
      score = Z[first - 1] + Y[i + 1];
    }
    ll upper, lower;
    if (second == 0)
    {
      upper = infty;
      lower = -infty;
    }
    else
    {
      ll FA = B[first];
      ll FB = B[first + second];
      lower = (FA + FB) / 2;
      ll GA = B[first + 1];
      ll GB = B[first + second + 1];
      upper = (GA + GB) / 2 + 1;
    }
    // cerr << "i = " << i << ", upper = " << upper << endl;
    while (it != S.end())
    {
      if (lower <= *it && *it <= upper)
      {
        M[*it] = score;
        it++;
      }
      else
      {
        break;
      }
    }
  }
  assert(it == S.end());
  flush();
}<commit_msg>tried D.cpp to 'D'<commit_after>/**
 * File    : D.cpp
 * Author  : Kazune Takahashi
 * Created : 1/12/2019, 9:15:17 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 100000000007;

int N, Q;
ll A[100010];
vector<ll> B;
ll X[100010];
set<ll> S;
map<ll, ll> M;
ll Y[100010];
ll Z[100010];

void flush()
{
  for (auto i = 0; i < Q; i++)
  {
    cout << M[X[i]] << endl;
  }
}

int main()
{
  cin >> N >> Q;
  for (auto i = 0; i < N; i++)
  {
    cin >> A[i];
  }
  for (auto i = 0; i < Q; i++)
  {
    cin >> X[i];
    S.insert(X[i]);
  }
  reverse(A, A + N);
  Y[N + 1] = 0;
  Y[N] = 0;
  Y[N - 1] = A[N - 1];
  Y[N - 2] = A[N - 2];
  for (auto i = N - 3; i >= 0; i--)
  {
    Y[i] = A[i] + Y[i + 2];
  }
  Z[0] = A[0];
  for (auto i = 1; i < N; i++)
  {
    Z[i] = A[i] + Z[i - 1];
  }
  B.push_back(infty);
  for (auto i = 0; i < N; i++)
  {
    B.push_back(A[i]);
  }
  B.push_back(-infty);
  auto it = S.begin();
  for (auto i = N; i >= 0; i--)
  {
    int second = i / 2;
    int first = i - second;
    ll score;
    if (first == 0)
    {
      score = Y[0];
    }
    else if (first == second)
    {
      score = Z[first - 1] + Y[i];
    }
    else
    {
      score = Z[first - 1] + Y[i + 1];
    }
    ll upper, lower;
    if (second == 0)
    {
      upper = infty;
      lower = -infty;
    }
    else
    {
      ll FA = B[first];
      ll FB = B[first + second];
      lower = (FA + FB) / 2;
      ll GA = B[first + 1];
      ll GB = B[first + second + 1];
      upper = (GA + GB) / 2 + 1;
    }
    cerr << "i = " << i << ", upper = " << upper << ", lower = " << lower << endl;
    while (it != S.end())
    {
      if (lower <= *it && *it <= upper)
      {
        M[*it] = score;
        it++;
      }
      else
      {
        break;
      }
    }
  }
  assert(it == S.end());
  flush();
}<|endoftext|>


<commit_before>#include "imageio.h"
#include "lodepng.h"
#include <ImfNamespace.h>
#include <ImfRgbaFile.h>
#include <ImfStringAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfArray.h>
#include "spectrum.h"
#include "geometry.h"

namespace IMF = OPENEXR_IMF_NAMESPACE;

void WriteOpenEXR(const char fileName[], IMF::Rgba* pixels, int w, int h) {
	IMF::RgbaOutputFile file(fileName, w, h, IMF::WRITE_RGBA);
	file.setFrameBuffer(pixels, 1, w);
	file.writePixels(h);
}

void ReadOpenEXR(const char fileName[],std::vector<IMF::Rgba> &pixels,int &width,int &height)
{
	IMF::RgbaInputFile file(fileName);
	Imath::Box2i dw = file.dataWindow();
	width = dw.max.x - dw.min.x + 1;
	height = dw.max.y - dw.min.y + 1;
	pixels.reserve(height*width);
	file.setFrameBuffer(&pixels[0] - dw.min.x - dw.min.y * width, 1, width);
	file.readPixels(dw.min.y, dw.max.y);
}

void WriteImageToFile(const char* fileName, Float* data, int w, int h) {
	const char* fileExt;
	const char *ptr, c = '.';
	//���һ������c��λ��
	ptr = strrchr(fileName, c);
	//��ָ����� �������
	int pos = ptr - fileName;
	//��ȡ��׺
	fileExt = &fileName[pos + 1];
	//�жϺ�׺�Ƿ���ͬ
	if (0 == strcmp(fileExt, "png") || 0 == strcmp(fileExt, "PNG")) {
		std::vector<uint8_t> image;
		for (int i = 0; i<w*h; ++i) {
			Float rgb[3];
			rgb[0] = data[i * 3];
			rgb[1] = data[i * 3 + 1];
			rgb[2] = data[i * 3 + 2];

			rgb[0] = GammaCorrect(rgb[0]);
			rgb[1] = GammaCorrect(rgb[1]);
			rgb[2] = GammaCorrect(rgb[2]);

			rgb[0] = Clamp(rgb[0], 0, 1);
			rgb[1] = Clamp(rgb[1], 0, 1);
			rgb[2] = Clamp(rgb[2], 0, 1);

			image.push_back(rgb[0] * 255);//R
			image.push_back(rgb[1] * 255);//G
			image.push_back(rgb[2] * 255);//B
			image.push_back(255);		//A
		}

		unsigned error = lodepng::encode(fileName, image, w, h);
		if (error) {
			LError << "encoder error " << error << ": " << lodepng_error_text(error);
		}
	}
	else if (0 == strcmp(fileExt, "exr") || 0 == strcmp(fileExt, "EXR")) {
		std::vector<IMF::Rgba> image;
		for (int i = 0; i<w*h; ++i) {
			image.push_back(IMF::Rgba{ data[i * 3] ,data[i * 3 + 1] ,data[i * 3 + 2] ,1 });
		}
		WriteOpenEXR(fileName, &image[0], w, h);
	}
}

std::unique_ptr<RGBSpectrum[]> ReadImage(const char* fileName, Point2i* resolution) {
	const char* fileExt;
	const char *ptr, c = '.';
	//���һ������c��λ��
	ptr = strrchr(fileName, c);
	//��ָ����� �������
	int pos = ptr - fileName;
	//��ȡ��׺
	fileExt = &fileName[pos + 1];
	//�жϺ�׺�Ƿ���ͬ
	if (0 == strcmp(fileExt, "png") || 0 == strcmp(fileExt, "PNG")) {
		std::vector<unsigned char> rawData;
		uint32_t width, height;
		uint32_t error = lodepng::decode(rawData, width, height, fileName);
		if (error) {
			return nullptr;
		}

		std::unique_ptr<RGBSpectrum[]> rgbData(new RGBSpectrum[width*height]);
		uint32_t index = 0;
		Float invDiv = 1.0 / 255.0;
		for (int j = 0; j<height; ++j) {
			for (int i = 0; i<width; ++i) {
				int k = i*height+j;
				rgbData[k][0] = rawData[0 + index] * invDiv;
				rgbData[k][1] = rawData[1 + index] * invDiv;
				rgbData[k][2] = rawData[2 + index] * invDiv;
				index += 4;//����4���ֽڣ���ΪPNG�ǰ���RGBA 4Byte*8Bit�ķ�ʽ��֯��
			}
		}
		if (resolution) {
			*resolution = Point2i(width, height);
		}
		return rgbData;
	}
	else if (0 == strcmp(fileExt, "exr") || 0 == strcmp(fileExt, "EXR")) {
		std::vector<IMF::Rgba> rawData;
		int width, height;
		ReadOpenEXR(fileName,rawData,width,height);
		std::unique_ptr<RGBSpectrum[]> rgbData(new RGBSpectrum[width*height]);

		for (int j = 0; j<height; ++j) {
			for (int i = 0; i<width; ++i) {
				int k = i+j*width;
				rgbData[k][0] = rawData[k].r;
				rgbData[k][1] = rawData[k].g;
				rgbData[k][2] = rawData[k].b;
			}
		}
		if (resolution) {
			*resolution = Point2i(width, height);
		}
		return rgbData;
	}

	return nullptr;

}
<commit_msg>修正下PNG格式在渲染器内的内存布局，交换了下v的上下<commit_after>#include "imageio.h"
#include "lodepng.h"
#include <ImfNamespace.h>
#include <ImfRgbaFile.h>
#include <ImfStringAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfArray.h>
#include "spectrum.h"
#include "geometry.h"

namespace IMF = OPENEXR_IMF_NAMESPACE;

void WriteOpenEXR(const char fileName[], IMF::Rgba* pixels, int w, int h) {
	IMF::RgbaOutputFile file(fileName, w, h, IMF::WRITE_RGBA);
	file.setFrameBuffer(pixels, 1, w);
	file.writePixels(h);
}

void ReadOpenEXR(const char fileName[],std::vector<IMF::Rgba> &pixels,int &width,int &height)
{
	IMF::RgbaInputFile file(fileName);
	Imath::Box2i dw = file.dataWindow();
	width = dw.max.x - dw.min.x + 1;
	height = dw.max.y - dw.min.y + 1;
	pixels.reserve(height*width);
	file.setFrameBuffer(&pixels[0] - dw.min.x - dw.min.y * width, 1, width);
	file.readPixels(dw.min.y, dw.max.y);
}

void WriteImageToFile(const char* fileName, Float* data, int w, int h) {
	const char* fileExt;
	const char *ptr, c = '.';
	//���һ������c��λ��
	ptr = strrchr(fileName, c);
	//��ָ����� �������
	int pos = ptr - fileName;
	//��ȡ��׺
	fileExt = &fileName[pos + 1];
	//�жϺ�׺�Ƿ���ͬ
	if (0 == strcmp(fileExt, "png") || 0 == strcmp(fileExt, "PNG")) {
		std::vector<uint8_t> image;
		for (int i = 0; i<w*h; ++i) {
			Float rgb[3];
			rgb[0] = data[i * 3];
			rgb[1] = data[i * 3 + 1];
			rgb[2] = data[i * 3 + 2];

			rgb[0] = GammaCorrect(rgb[0]);
			rgb[1] = GammaCorrect(rgb[1]);
			rgb[2] = GammaCorrect(rgb[2]);

			rgb[0] = Clamp(rgb[0], 0, 1);
			rgb[1] = Clamp(rgb[1], 0, 1);
			rgb[2] = Clamp(rgb[2], 0, 1);

			image.push_back(rgb[0] * 255);//R
			image.push_back(rgb[1] * 255);//G
			image.push_back(rgb[2] * 255);//B
			image.push_back(255);		//A
		}

		unsigned error = lodepng::encode(fileName, image, w, h);
		if (error) {
			LError << "encoder error " << error << ": " << lodepng_error_text(error);
		}
	}
	else if (0 == strcmp(fileExt, "exr") || 0 == strcmp(fileExt, "EXR")) {
		std::vector<IMF::Rgba> image;
		for (int i = 0; i<w*h; ++i) {
			image.push_back(IMF::Rgba{ data[i * 3] ,data[i * 3 + 1] ,data[i * 3 + 2] ,1 });
		}
		WriteOpenEXR(fileName, &image[0], w, h);
	}
}

std::unique_ptr<RGBSpectrum[]> ReadImage(const char* fileName, Point2i* resolution) {
	const char* fileExt;
	const char *ptr, c = '.';
	//���һ������c��λ��
	ptr = strrchr(fileName, c);
	//��ָ����� �������
	int pos = ptr - fileName;
	//��ȡ��׺
	fileExt = &fileName[pos + 1];
	//�жϺ�׺�Ƿ���ͬ
	if (0 == strcmp(fileExt, "png") || 0 == strcmp(fileExt, "PNG")) {
		std::vector<unsigned char> rawData;
		uint32_t width, height;
		uint32_t error = lodepng::decode(rawData, width, height, fileName);
		if (error) {
			return nullptr;
		}

		std::unique_ptr<RGBSpectrum[]> rgbData(new RGBSpectrum[width*height]);
		uint32_t index = 0;
		Float invDiv = 1.0 / 255.0;
		for (int j = 0; j<height; ++j) {
			for (int i = 0; i<width; ++i) {
				int k = i*height+(height-1-j);
				//nt k=width*j+i;
				rgbData[k][0] = rawData[0 + index] * invDiv;
				rgbData[k][1] = rawData[1 + index] * invDiv;
				rgbData[k][2] = rawData[2 + index] * invDiv;
				index += 4;//����4���ֽڣ���ΪPNG�ǰ���RGBA 4Byte*8Bit�ķ�ʽ��֯��
			}
		}
		if (resolution) {
			*resolution = Point2i(width, height);
		}
		return rgbData;
	}
	else if (0 == strcmp(fileExt, "exr") || 0 == strcmp(fileExt, "EXR")) {
		std::vector<IMF::Rgba> rawData;
		int width, height;
		ReadOpenEXR(fileName,rawData,width,height);
		std::unique_ptr<RGBSpectrum[]> rgbData(new RGBSpectrum[width*height]);

		for (int j = 0; j<height; ++j) {
			for (int i = 0; i<width; ++i) {
				int k = i+j*width;
				rgbData[k][0] = rawData[k].r;
				rgbData[k][1] = rawData[k].g;
				rgbData[k][2] = rawData[k].b;
			}
		}
		if (resolution) {
			*resolution = Point2i(width, height);
		}
		return rgbData;
	}

	return nullptr;

}
<|endoftext|>