<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// aggregation.cpp
//
// Identification: src/codegen/aggregation.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/aggregation.h"
#include "codegen/if.h"
#include "codegen/type.h"

namespace peloton {
namespace codegen {

//===----------------------------------------------------------------------===//
// Setup the aggregation storage format given the aggregates the caller wants to
// store.
//===----------------------------------------------------------------------===//
void Aggregation::Setup(
    CodeGen &codegen,
    const std::vector<planner::AggregatePlan::AggTerm> &aggregates) {
  // Collect the types so we can configure the updateable storage's format
  bool needs_group_count = false;
  bool tracks_group_count = false;
  for (uint32_t i = 0; i < aggregates.size(); i++) {
    const auto agg_term = aggregates[i];
    // Defense > Offense ?
    PL_ASSERT(agg_term.agg_ai.type != type::Type::TypeId::INVALID);

    needs_group_count |= agg_term.aggtype == ExpressionType::AGGREGATE_AVG;
    tracks_group_count |=
        agg_term.aggtype == ExpressionType::AGGREGATE_COUNT_STAR;
  }

  // Add the count(*) aggregate first, if we need to
  if (tracks_group_count || needs_group_count) {
    uint32_t storage_pos = storage_.AddType(type::Type::TypeId::BIGINT);
    AggregateInfo count_agg{
        ExpressionType::AGGREGATE_COUNT_STAR, type::Type::TypeId::BIGINT,
        std::numeric_limits<uint32_t>::max(), storage_pos, true};
    aggregate_infos_.push_back(count_agg);
  }

  // Add the rest
  for (uint32_t source_idx = 0; source_idx < aggregates.size(); source_idx++) {
    const auto agg_term = aggregates[source_idx];
    switch (agg_term.aggtype) {
      case ExpressionType::AGGREGATE_COUNT: {
        // We're counting instances ... use BIGINT for the count
        const auto count_type = type::Type::TypeId::BIGINT;
        uint32_t storage_pos = storage_.AddType(count_type);
        AggregateInfo aggregate_info{agg_term.aggtype, count_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // Count() - to check whether there is no item at all
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_idx,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // Regular
        const auto value_type = agg_term.expression->GetValueType();
        uint32_t storage_pos = storage_.AddType(value_type);
        AggregateInfo aggregate_info{agg_term.aggtype, value_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // We decompose averages (i.e., AVG(c)) into COUNT(c) and SUM(c)

        // SUM() - the type must match the type of the expression
        PL_ASSERT(agg_term.expression != nullptr);
        const auto sum_type = agg_term.expression->GetValueType();
        uint32_t sum_storage_pos = storage_.AddType(sum_type);
        AggregateInfo sum_agg{ExpressionType::AGGREGATE_SUM, sum_type,
                              source_idx, sum_storage_pos, true};
        aggregate_infos_.push_back(sum_agg);

        // COUNT() - can use big integer since we're counting instances
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_idx,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // AVG()
        // TODO: Is this always double?
        AggregateInfo avg_agg{agg_term.aggtype, type::Type::TypeId::DECIMAL,
                              source_idx, std::numeric_limits<uint32_t>::max(),
                              false};
        aggregate_infos_.push_back(avg_agg);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // count(*)'s are always stored in the first slot, reference that here
        // NOTE: We've already added the count(*) to the storage format above,
        //       don't do it here
        PL_ASSERT(tracks_group_count);
        AggregateInfo count_agg{agg_term.aggtype, type::Type::TypeId::BIGINT,
                                source_idx, 0, false};
        aggregate_infos_.push_back(count_agg);
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when preparing aggregator",
            ExpressionTypeToString(agg_term.aggtype).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }

  // Finalize the storage format
  storage_.Finalize(codegen);
}

// Create the initial values of all aggregates based on the the provided values
void Aggregation::CreateInitialValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &initial) const {
  // TODO: Handle null
  for (size_t i = 0; i < aggregate_infos_.size(); i++) {
    const auto &aggregate_info = aggregate_infos_[i];
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // For the above aggregations, the initial value is the attribute value
        uint32_t val_source = aggregate_info.source_index;
        storage_.SetValueAt(codegen, storage_space,
                            aggregate_info.storage_index, initial[val_source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // TODO: Count(col) needs to check for null values
        // This aggregate should be moved to the front of the storage area
        storage_.SetValueAt(
            codegen, storage_space, aggregate_info.storage_index,
            codegen::Value{type::Type::TypeId::BIGINT, codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when creating initial values",
            ExpressionTypeToString(aggregate_info.aggregate_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

//===----------------------------------------------------------------------===//
// Advance each of the aggregates stored in the provided storage space. We
// use the storage format class to determine the location of each of the
// aggregates. Then, depending on the type of aggregation, we advance of their
// values, populating the provided next_vals vector with their new values.
//===----------------------------------------------------------------------===//
void Aggregation::AdvanceValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &next_vals) const {
  // TODO: Handle null
  for (const auto &aggregate_info : aggregate_infos_) {
    // Loop over all aggregates, advancing each
    uint32_t source = aggregate_info.source_index;
    codegen::Value next;
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MIN: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Min(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MAX: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Max(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        auto delta = Value{type::Type::TypeId::BIGINT, codegen.Const64(1)};
        next = curr.Add(codegen, delta);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // COUNT(*) is always stored first with a source equal to INT_MAX. All
        // other COUNT(*)'s refer to that one.
        if (source != std::numeric_limits<uint32_t>::max()) {
          continue;
        }
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        auto delta = Value{type::Type::TypeId::BIGINT, codegen.Const64(1)};
        next = curr.Add(codegen, delta);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        continue;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when advancing aggregator",
            ExpressionTypeToString(aggregate_info.aggregate_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }

    // StoreValue the next value in the appropriate slot
    PL_ASSERT(next.GetType() != type::Type::TypeId::INVALID);
    storage_.SetValueAt(codegen, storage_space, aggregate_info.storage_index,
                        next);
  }
}

//===----------------------------------------------------------------------===//
// This function will finalize the aggregates stored in the provided storage
// space.  Finalization essentially means computing the final values of the
// aggregates. This is only really necessary for averages. Either way, we
// populate the final_vals vector with the final values of all the aggregates.
//===----------------------------------------------------------------------===//
void Aggregation::FinalizeValues(
    CodeGen &codegen, llvm::Value *storage_space,
    std::vector<codegen::Value> &final_vals) const {
  // Collect all final values into this map. We need this because some
  // aggregates are derived from other component aggregates.
  std::map<std::pair<uint32_t, ExpressionType>, codegen::Value> vals;

  for (const auto &aggregate_info : aggregate_infos_) {
    uint32_t source = aggregate_info.source_index;
    ExpressionType agg_type = aggregate_info.aggregate_type;
    switch (agg_type) {
      case ExpressionType::AGGREGATE_COUNT: {
        codegen::Value final_val = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);
        vals[std::make_pair(source, agg_type)] = final_val;
        if (!aggregate_info.is_internal) {
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        codegen::Value count =
            vals[std::make_pair(source, ExpressionType::AGGREGATE_COUNT)];
        codegen::Value final_calc = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);

        vals[std::make_pair(source, agg_type)] = final_calc;
        if (!aggregate_info.is_internal) {
          // Empty check
          codegen::Value zero{type::Type::TypeId::INTEGER, codegen.Const32(0)};
          codegen::Value zero_count = count.CompareEq(codegen, zero);

          codegen::Value final_null;
          If check_count{codegen, zero_count.GetValue()};
          {
            final_null = Type::GetNullValue(codegen, final_calc.GetType());
          }
          check_count.EndIf();
          auto final_val = check_count.BuildPHI(final_null, final_calc);
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // Find the sum and count for this aggregate
        codegen::Value count = vals[{source, ExpressionType::AGGREGATE_COUNT}];
        count = count.CastTo(codegen, type::Type::TypeId::DECIMAL);

        codegen::Value sum = vals[{source, ExpressionType::AGGREGATE_SUM}];
        sum = sum.CastTo(codegen, type::Type::TypeId::DECIMAL);

        codegen::Value final_val =
            sum.Div(codegen, count, Value::OnError::ReturnNull);

        vals[std::make_pair(source, agg_type)] = final_val;
        final_vals.push_back(final_val);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        if (source != std::numeric_limits<uint32_t>::max()) {
          PL_ASSERT(!aggregate_info.is_internal);
          uint32_t count_source = std::numeric_limits<uint32_t>::max();
          final_vals.push_back(vals[std::make_pair(count_source, agg_type)]);
        } else {
          PL_ASSERT(aggregate_info.is_internal);
          codegen::Value final_val = storage_.GetValueAt(
              codegen, storage_space, aggregate_info.storage_index);
          vals[std::make_pair(source, agg_type)] = final_val;
        }
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when finalizing aggregator",
            ExpressionTypeToString(agg_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

}  // namespace codegen
}  // namespace peloton
<commit_msg>Code consistency - formatting<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// aggregation.cpp
//
// Identification: src/codegen/aggregation.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "codegen/aggregation.h"
#include "codegen/if.h"
#include "codegen/type.h"

namespace peloton {
namespace codegen {

//===----------------------------------------------------------------------===//
// Setup the aggregation storage format given the aggregates the caller wants to
// store.
//===----------------------------------------------------------------------===//
void Aggregation::Setup(
    CodeGen &codegen,
    const std::vector<planner::AggregatePlan::AggTerm> &aggregates) {
  // Collect the types so we can configure the updateable storage's format
  bool needs_group_count = false;
  bool tracks_group_count = false;
  for (uint32_t i = 0; i < aggregates.size(); i++) {
    const auto agg_term = aggregates[i];
    // Defense > Offense ?
    PL_ASSERT(agg_term.agg_ai.type != type::Type::TypeId::INVALID);

    needs_group_count |= agg_term.aggtype == ExpressionType::AGGREGATE_AVG;
    tracks_group_count |=
        agg_term.aggtype == ExpressionType::AGGREGATE_COUNT_STAR;
  }

  // Add the count(*) aggregate first, if we need to
  if (tracks_group_count || needs_group_count) {
    uint32_t storage_pos = storage_.AddType(type::Type::TypeId::BIGINT);
    AggregateInfo count_agg{
        ExpressionType::AGGREGATE_COUNT_STAR, type::Type::TypeId::BIGINT,
        std::numeric_limits<uint32_t>::max(), storage_pos, true};
    aggregate_infos_.push_back(count_agg);
  }

  // Add the rest
  for (uint32_t source_idx = 0; source_idx < aggregates.size(); source_idx++) {
    const auto agg_term = aggregates[source_idx];
    switch (agg_term.aggtype) {
      case ExpressionType::AGGREGATE_COUNT: {
        // We're counting instances ... use BIGINT for the count
        const auto count_type = type::Type::TypeId::BIGINT;
        uint32_t storage_pos = storage_.AddType(count_type);
        AggregateInfo aggregate_info{agg_term.aggtype, count_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // Count() - to check whether there is no item at all
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_idx,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // Regular
        const auto value_type = agg_term.expression->GetValueType();
        uint32_t storage_pos = storage_.AddType(value_type);
        AggregateInfo aggregate_info{agg_term.aggtype, value_type, source_idx,
                                     storage_pos, false};
        aggregate_infos_.push_back(aggregate_info);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // We decompose averages (i.e., AVG(c)) into COUNT(c) and SUM(c)

        // SUM() - the type must match the type of the expression
        PL_ASSERT(agg_term.expression != nullptr);
        const auto sum_type = agg_term.expression->GetValueType();
        uint32_t sum_storage_pos = storage_.AddType(sum_type);
        AggregateInfo sum_agg{ExpressionType::AGGREGATE_SUM, sum_type,
                              source_idx, sum_storage_pos, true};
        aggregate_infos_.push_back(sum_agg);

        // COUNT() - can use big integer since we're counting instances
        uint32_t count_storage_pos =
            storage_.AddType(type::Type::TypeId::BIGINT);
        AggregateInfo count_agg{ExpressionType::AGGREGATE_COUNT,
                                type::Type::TypeId::BIGINT, source_idx,
                                count_storage_pos, true};
        aggregate_infos_.push_back(count_agg);

        // AVG()
        // TODO: Is this always double?
        AggregateInfo avg_agg{agg_term.aggtype, type::Type::TypeId::DECIMAL,
                              source_idx, std::numeric_limits<uint32_t>::max(),
                              false};
        aggregate_infos_.push_back(avg_agg);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // count(*)'s are always stored in the first slot, reference that here
        // NOTE: We've already added the count(*) to the storage format above,
        //       don't do it here
        PL_ASSERT(tracks_group_count);
        AggregateInfo count_agg{agg_term.aggtype, type::Type::TypeId::BIGINT,
                                source_idx, 0, false};
        aggregate_infos_.push_back(count_agg);
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when preparing aggregator",
            ExpressionTypeToString(agg_term.aggtype).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }

  // Finalize the storage format
  storage_.Finalize(codegen);
}

// Create the initial values of all aggregates based on the the provided values
void Aggregation::CreateInitialValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &initial) const {
  // TODO: Handle null
  for (size_t i = 0; i < aggregate_infos_.size(); i++) {
    const auto &aggregate_info = aggregate_infos_[i];
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        // For the above aggregations, the initial value is the attribute value
        uint32_t val_source = aggregate_info.source_index;
        storage_.SetValueAt(codegen, storage_space,
                            aggregate_info.storage_index, initial[val_source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT:
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // TODO: Count(col) needs to check for null values
        // This aggregate should be moved to the front of the storage area
        storage_.SetValueAt(
            codegen, storage_space, aggregate_info.storage_index,
            codegen::Value{type::Type::TypeId::BIGINT, codegen.Const64(1)});
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when creating initial values",
            ExpressionTypeToString(aggregate_info.aggregate_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

//===----------------------------------------------------------------------===//
// Advance each of the aggregates stored in the provided storage space. We
// use the storage format class to determine the location of each of the
// aggregates. Then, depending on the type of aggregation, we advance of their
// values, populating the provided next_vals vector with their new values.
//===----------------------------------------------------------------------===//
void Aggregation::AdvanceValues(
    CodeGen &codegen, llvm::Value *storage_space,
    const std::vector<codegen::Value> &next_vals) const {
  // TODO: Handle null
  for (const auto &aggregate_info : aggregate_infos_) {
    // Loop over all aggregates, advancing each
    uint32_t source = aggregate_info.source_index;
    codegen::Value next;
    switch (aggregate_info.aggregate_type) {
      case ExpressionType::AGGREGATE_SUM: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Add(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MIN: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Min(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_MAX: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        next = curr.Max(codegen, next_vals[source]);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT: {
        PL_ASSERT(source < std::numeric_limits<uint32_t>::max());
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        auto delta = Value{type::Type::TypeId::BIGINT, codegen.Const64(1)};
        next = curr.Add(codegen, delta);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        // COUNT(*) is always stored first with a source equal to INT_MAX. All
        // other COUNT(*)'s refer to that one.
        if (source != std::numeric_limits<uint32_t>::max()) {
          continue;
        }
        auto curr = storage_.GetValueAt(codegen, storage_space,
                                        aggregate_info.storage_index);
        auto delta = Value{type::Type::TypeId::BIGINT, codegen.Const64(1)};
        next = curr.Add(codegen, delta);
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // AVG() aggregates aren't physically stored
        continue;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when advancing aggregator",
            ExpressionTypeToString(aggregate_info.aggregate_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }

    // StoreValue the next value in the appropriate slot
    PL_ASSERT(next.GetType() != type::Type::TypeId::INVALID);
    storage_.SetValueAt(codegen, storage_space, aggregate_info.storage_index,
                        next);
  }
}

//===----------------------------------------------------------------------===//
// This function will finalize the aggregates stored in the provided storage
// space.  Finalization essentially means computing the final values of the
// aggregates. This is only really necessary for averages. Either way, we
// populate the final_vals vector with the final values of all the aggregates.
//===----------------------------------------------------------------------===//
void Aggregation::FinalizeValues(
    CodeGen &codegen, llvm::Value *storage_space,
    std::vector<codegen::Value> &final_vals) const {
  // Collect all final values into this map. We need this because some
  // aggregates are derived from other component aggregates.
  std::map<std::pair<uint32_t, ExpressionType>, codegen::Value> vals;

  for (const auto &aggregate_info : aggregate_infos_) {
    uint32_t source = aggregate_info.source_index;
    ExpressionType agg_type = aggregate_info.aggregate_type;
    switch (agg_type) {
      case ExpressionType::AGGREGATE_COUNT: {
        codegen::Value final_val = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);
        vals[std::make_pair(source, agg_type)] = final_val;
        if (!aggregate_info.is_internal) {
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_SUM:
      case ExpressionType::AGGREGATE_MIN:
      case ExpressionType::AGGREGATE_MAX: {
        codegen::Value count = vals[{source, ExpressionType::AGGREGATE_COUNT}];
        codegen::Value final_calc = storage_.GetValueAt(
            codegen, storage_space, aggregate_info.storage_index);

        vals[std::make_pair(source, agg_type)] = final_calc;
        if (!aggregate_info.is_internal) {
          // Empty check
          codegen::Value zero{type::Type::TypeId::INTEGER, codegen.Const32(0)};
          codegen::Value zero_count = count.CompareEq(codegen, zero);

          codegen::Value final_null;
          If check_count{codegen, zero_count.GetValue()};
          {
            final_null = Type::GetNullValue(codegen, final_calc.GetType());
          }
          check_count.EndIf();
          auto final_val = check_count.BuildPHI(final_null, final_calc);
          final_vals.push_back(final_val);
        }
        break;
      }
      case ExpressionType::AGGREGATE_AVG: {
        // Find the sum and count for this aggregate
        codegen::Value count = vals[{source, ExpressionType::AGGREGATE_COUNT}];
        count = count.CastTo(codegen, type::Type::TypeId::DECIMAL);

        codegen::Value sum = vals[{source, ExpressionType::AGGREGATE_SUM}];
        sum = sum.CastTo(codegen, type::Type::TypeId::DECIMAL);

        codegen::Value final_val =
            sum.Div(codegen, count, Value::OnError::ReturnNull);

        vals[std::make_pair(source, agg_type)] = final_val;
        final_vals.push_back(final_val);
        break;
      }
      case ExpressionType::AGGREGATE_COUNT_STAR: {
        if (source != std::numeric_limits<uint32_t>::max()) {
          PL_ASSERT(!aggregate_info.is_internal);
          uint32_t count_source = std::numeric_limits<uint32_t>::max();
          final_vals.push_back(vals[std::make_pair(count_source, agg_type)]);
        } else {
          PL_ASSERT(aggregate_info.is_internal);
          codegen::Value final_val = storage_.GetValueAt(
              codegen, storage_space, aggregate_info.storage_index);
          vals[std::make_pair(source, agg_type)] = final_val;
        }
        break;
      }
      default: {
        std::string message = StringUtil::Format(
            "Unexpected aggregate type [%s] when finalizing aggregator",
            ExpressionTypeToString(agg_type).c_str());
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

}  // namespace codegen
}  // namespace peloton
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// FILE HEADER
#include <dali-toolkit/internal/text/character-set-conversion.h>

namespace Dali
{

namespace Toolkit
{

namespace
{
  const static uint8_t U1 = 1u;
  const static uint8_t U2 = 2u;
  const static uint8_t U3 = 3u;
  const static uint8_t U4 = 4u;
  const static uint8_t U0 = 0u;
  const static uint8_t UTF8_LENGTH[256] = {
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, // lead byte = 0xxx xxxx (U+0000 - U+007F + some extended ascii characters)
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1,                                 //

    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, // lead byte = 110x xxxx (U+0080 - U+07FF)
    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
    U2, U2,                                 //

    U3, U3, U3, U3, U3, U3, U3, U3, U3, U3, // lead byte = 1110 xxxx (U+0800 - U+FFFF)
    U3, U3, U3, U3, U3, U3,                 //

    U4, U4, U4, U4, U4, U4, U4, U4,         // lead byte = 1111 0xxx (U+10000 - U+1FFFFF)

    U0, U0, U0, U0,                         // Non valid.
    U0, U0, U0, U0,                         // Non valid.
  };
} // namespace

uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length )
{
  uint32_t numberOfCharacters = 0u;

  const uint8_t* begin = utf8;
  const uint8_t* end = utf8 + length;

  for( ; begin < end ; begin += UTF8_LENGTH[*begin], ++numberOfCharacters );

  return numberOfCharacters;
}

uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters )
{
  uint32_t numberOfBytes = 0u;

  const uint32_t* begin = utf32;
  const uint32_t* end = utf32 + numberOfCharacters;

  for( ; begin < end; ++begin )
  {
    const uint32_t code = *begin;

    if( code < 0x80u )
    {
      ++numberOfBytes;
    }
    else if( code < 0x800u )
    {
      numberOfBytes += U2;
    }
    else if( code < 0x10000u )
    {
      numberOfBytes += U3;
    }
    else if( code < 0x200000u )
    {
      numberOfBytes += U4;
    }
  }

  return numberOfBytes;
}

uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 )
{
  uint32_t numberOfCharacters = 0u;

  const uint8_t* begin = utf8;
  const uint8_t* end = utf8 + length;

  for( ; begin < end ; ++numberOfCharacters )
  {
    const uint8_t leadByte = *begin;

    switch( UTF8_LENGTH[leadByte] )
    {
      case U1:
      {
        *utf32++ = leadByte;
        begin++;
        break;
      }

      case U2:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x1fu;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }

      case U3:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x1fu;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }

      case U4:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x1fu;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }
    }
  }

  return numberOfCharacters;
}

void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 )
{
  const uint32_t* begin = utf32;
  const uint32_t* end = utf32 + numberOfCharacters;

  for( ; begin < end; ++begin )
  {
    const uint32_t code = *begin;

    if( code < 0x80u )
    {
      *utf8++ = code;
    }
    else if( code < 0x800u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 6u )           | 0xc0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
    else if( code < 0x10000u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 12u )          | 0xe0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
    else if( code < 0x200000u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 18u )          | 0xf0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>( ( code >> 12u ) & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
  }
}

} // namespace Toolkit

} // namespace Dali
<commit_msg>Corrected UTF-8 to UTF-32 conversion<commit_after>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// FILE HEADER
#include <dali-toolkit/internal/text/character-set-conversion.h>

namespace Dali
{

namespace Toolkit
{

namespace
{
  const static uint8_t U1 = 1u;
  const static uint8_t U2 = 2u;
  const static uint8_t U3 = 3u;
  const static uint8_t U4 = 4u;
  const static uint8_t U0 = 0u;
  const static uint8_t UTF8_LENGTH[256] = {
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, // lead byte = 0xxx xxxx (U+0000 - U+007F + some extended ascii characters)
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
    U1, U1,                                 //

    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, // lead byte = 110x xxxx (U+0080 - U+07FF)
    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
    U2, U2,                                 //

    U3, U3, U3, U3, U3, U3, U3, U3, U3, U3, // lead byte = 1110 xxxx (U+0800 - U+FFFF)
    U3, U3, U3, U3, U3, U3,                 //

    U4, U4, U4, U4, U4, U4, U4, U4,         // lead byte = 1111 0xxx (U+10000 - U+1FFFFF)

    U0, U0, U0, U0,                         // Non valid.
    U0, U0, U0, U0,                         // Non valid.
  };
} // namespace

uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length )
{
  uint32_t numberOfCharacters = 0u;

  const uint8_t* begin = utf8;
  const uint8_t* end = utf8 + length;

  for( ; begin < end ; begin += UTF8_LENGTH[*begin], ++numberOfCharacters );

  return numberOfCharacters;
}

uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters )
{
  uint32_t numberOfBytes = 0u;

  const uint32_t* begin = utf32;
  const uint32_t* end = utf32 + numberOfCharacters;

  for( ; begin < end; ++begin )
  {
    const uint32_t code = *begin;

    if( code < 0x80u )
    {
      ++numberOfBytes;
    }
    else if( code < 0x800u )
    {
      numberOfBytes += U2;
    }
    else if( code < 0x10000u )
    {
      numberOfBytes += U3;
    }
    else if( code < 0x200000u )
    {
      numberOfBytes += U4;
    }
  }

  return numberOfBytes;
}

uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 )
{
  uint32_t numberOfCharacters = 0u;

  const uint8_t* begin = utf8;
  const uint8_t* end = utf8 + length;

  for( ; begin < end ; ++numberOfCharacters )
  {
    const uint8_t leadByte = *begin;

    switch( UTF8_LENGTH[leadByte] )
    {
      case U1:
      {
        *utf32++ = leadByte;
        begin++;
        break;
      }

      case U2:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x1fu;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }

      case U3:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x0fu;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }

      case U4:
      {
        uint32_t& code = *utf32++;
        code = leadByte & 0x07u;
        begin++;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        code <<= 6u;
        code |= *begin++ & 0x3fu;
        break;
      }
    }
  }

  return numberOfCharacters;
}

void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 )
{
  const uint32_t* begin = utf32;
  const uint32_t* end = utf32 + numberOfCharacters;

  for( ; begin < end; ++begin )
  {
    const uint32_t code = *begin;

    if( code < 0x80u )
    {
      *utf8++ = code;
    }
    else if( code < 0x800u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 6u )           | 0xc0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
    else if( code < 0x10000u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 12u )          | 0xe0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
    else if( code < 0x200000u )
    {
      *utf8++ = static_cast<uint8_t>(   code >> 18u )          | 0xf0u; // lead byte for 2 byte sequence
      *utf8++ = static_cast<uint8_t>( ( code >> 12u ) & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
    }
  }
}

} // namespace Toolkit

} // namespace Dali
<|endoftext|>


<commit_before>
#include "../../Flare.h"
#include "FlareOrbitalMenu.h"
#include "../../Game/FlareGame.h"
#include "../../Player/FlareMenuManager.h"
#include "../../Player/FlarePlayerController.h"

#define LOCTEXT_NAMESPACE "FlareOrbitalMenu"

/*----------------------------------------------------
	Construct
----------------------------------------------------*/

void SFlareOrbitalMenu::Construct(const FArguments& InArgs)
{
	// Data
	MenuManager = InArgs._MenuManager;
	const FFlareStyleCatalog& Theme = FFlareStyleSet::GetDefaultTheme();
	Game = MenuManager->GetPC()->GetGame();

	// Build structure
	ChildSlot
	.HAlign(HAlign_Fill)
	.VAlign(VAlign_Fill)
	[
		SNew(SVerticalBox)

		+ SVerticalBox::Slot()
		.AutoHeight()
		.HAlign(HAlign_Fill)
		.VAlign(VAlign_Center)
		.Padding(Theme.ContentPadding)
		[
			SNew(SHorizontalBox)

			// Icon
			+ SHorizontalBox::Slot()
			.AutoWidth()
			[
				SNew(SImage).Image(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Orbit))
			]

			// Title
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.Padding(Theme.ContentPadding)
			[
				SNew(STextBlock)
				.TextStyle(&Theme.TitleFont)
				.Text(LOCTEXT("Orbital", "ORBITAL MAP"))
			]

			// Quit
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("Leaderboard", "Leaderboard"))
				.ToolTipText(LOCTEXT("LeaderboardInfo", "Take a look at the companies"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Leaderboard, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnOpenLeaderboard)
			]

			// Quit
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("SaveQuit", "Save and quit"))
				.ToolTipText(LOCTEXT("SaveQuitInfo", "Save the game and go back to the main menu"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Main, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnMainMenu)
			]

			// Close
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("Close", "Close"))
				.ToolTipText(LOCTEXT("CloseInfo", "Close the menu and go back to flying the ship"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Exit, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnExit)
			]
		]

		// Separator
		+ SVerticalBox::Slot()
		.AutoHeight()
		.Padding(FMargin(200, 20))
		[
			SNew(SImage).Image(&Theme.SeparatorBrush)
		]

		// Content
		+ SVerticalBox::Slot()
		.AutoHeight()
		.Padding(Theme.ContentPadding)
		[
			SAssignNew(SectorsBox, SHorizontalBox)
		]
	];

}

/*----------------------------------------------------
	Interaction
----------------------------------------------------*/

void SFlareOrbitalMenu::Setup()
{
	SetEnabled(false);
	SetVisibility(EVisibility::Hidden);
}

void SFlareOrbitalMenu::Enter()
{
	FLOG("SFlareOrbitalMenu::Enter");
	SetEnabled(true);
	SetVisibility(EVisibility::Visible);

	Game->DeactivateSector(MenuManager->GetPC());

	// Add sectors slots
	for (int32 SectorIndex = 0; SectorIndex < Game->GetGameWorld()->GetSectors().Num(); SectorIndex++)
	{
		TSharedPtr<int32> IndexPtr(new int32(SectorIndex));

		UFlareSimulatedSector* Sector = Game->GetGameWorld()->GetSectors()[SectorIndex];

		SectorsBox->AddSlot()
		[
			SNew(SFlareRoundButton)
			.Text(FText::FromString(Sector->GetSectorName()))
			.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_None, true))
			.OnClicked(this, &SFlareOrbitalMenu::OnOpenSector, IndexPtr)
		];
	}
}

void SFlareOrbitalMenu::Exit()
{
	SetEnabled(false);
	SetVisibility(EVisibility::Hidden);

	SectorsBox->ClearChildren();
}

/*----------------------------------------------------
	Drawing
----------------------------------------------------*/

int32 SFlareOrbitalMenu::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
	FVector2D PlanetCenter = ClippingRect.GetSize() / 2;

	DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 200, 0, 200, 360);

	//DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 350, 45, 300, 225);

	//DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 350, -90, 300, 90);

	return SCompoundWidget::OnPaint(Args, AllottedGeometry, ClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}

void SFlareOrbitalMenu::DrawOrbitPath(const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
	FVector2D PlanetCenter, int32 RadiusA, int32 AngleA, int32 RadiusB, int32 AngleB) const
{
	// Setup initial data
	float InitialDistance = AngleB - AngleA;
	int32 InitialAngleA = AngleA;
	int32 DrawnDistance = 0;
	int32 DrawnSegments = 0;
	int32 MaxAngleInSegment = 90;

	// Compute initial points
	FVector2D PointA = GetPositionFromPolar(RadiusA, AngleA);
	FVector2D PointB = GetPositionFromPolar(RadiusB, AngleB);

	// Draw a series of segments until the path has been done.
	do
	{
		// Compute intermediate angles
		int32 CurrentAngleA = AngleA + DrawnSegments * MaxAngleInSegment;
		int32 CurrentAngleB = FMath::Min(CurrentAngleA + MaxAngleInSegment, AngleB);
		float CurrentAngleARad = FMath::DegreesToRadians(CurrentAngleA - InitialAngleA);
		float CurrentAngleBRad = FMath::DegreesToRadians(CurrentAngleB - InitialAngleA);

		// Polar equation of an ellipse : point A
		float CurrentRadiusA = (RadiusA * RadiusB) / FMath::Sqrt(
			FMath::Square(RadiusB * FMath::Cos(CurrentAngleARad)) +
			FMath::Square(RadiusA * FMath::Sin(CurrentAngleARad))
			);
		FVector2D CurrentPointA = GetPositionFromPolar(CurrentRadiusA, CurrentAngleA);;

		// Polar equation of an ellipse : point B
		float CurrentRadiusB = (RadiusA * RadiusB) / FMath::Sqrt(
			FMath::Square(RadiusB * FMath::Cos(CurrentAngleBRad)) +
			FMath::Square(RadiusA * FMath::Sin(CurrentAngleBRad))
			);
		FVector2D CurrentPointB = GetPositionFromPolar(CurrentRadiusB, CurrentAngleB);

		// Tangents vary depending on the angle and ellipse parameters
		float TangentSubdivisionRatio = ((CurrentAngleB - CurrentAngleA) / 90.0f);
		float TangentLength = TangentSubdivisionRatio * FMath::Sqrt(2);// *(1 + 0.3 * FMath::Sin((PI * (CurrentAngleA - InitialAngleA)) / 180));

		 // Compute intermediate tangents
		FVector2D CurrentTangentA = TangentLength * FVector2D(-CurrentPointA.Y, CurrentPointA.X);
		FVector2D CurrentTangentB = TangentLength * FVector2D(-CurrentPointB.Y, CurrentPointB.X);

		// Draw
		DrawOrbitSegment(ClippingRect, OutDrawElements, LayerId, PlanetCenter, CurrentPointA, CurrentTangentA, CurrentPointB, CurrentTangentB);
		DrawnDistance += (CurrentAngleB - CurrentAngleA);
		DrawnSegments++;

	} while (DrawnDistance < InitialDistance);
}

void SFlareOrbitalMenu::DrawOrbitSegment(const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
	FVector2D PlanetCenter, FVector2D PointA, FVector2D TangentA, FVector2D PointB, FVector2D TangentB) const
{
	// Get the rendering parametrs
	const FFlareStyleCatalog& Theme = FFlareStyleSet::GetDefaultTheme();
	FLinearColor WireColor = Theme.NeutralColor;
	WireColor.A = Theme.DefaultAlpha;

	// Draw
	FSlateDrawElement::MakeDrawSpaceSpline(
		OutDrawElements,
		LayerId,
		PlanetCenter + PointA,
		TangentA,
		PlanetCenter + PointB,
		TangentB,
		ClippingRect,
		8,
		ESlateDrawEffect::None,
		WireColor
		);
}

inline FVector2D SFlareOrbitalMenu::GetPositionFromPolar(int32 Radius, int32 Angle) const
{
	float X, Y;
	FMath::PolarToCartesian(Radius, FMath::DegreesToRadians(Angle), X, Y);
	return FVector2D(X, Y);
}

/*----------------------------------------------------
	Callbacks
----------------------------------------------------*/

void SFlareOrbitalMenu::OnOpenLeaderboard()
{
	MenuManager->OpenMenu(EFlareMenu::MENU_Leaderboard);
}

void SFlareOrbitalMenu::OnMainMenu()
{
	AFlarePlayerController* PC = MenuManager->GetPC();

	PC->GetGame()->SaveGame(PC);
	PC->GetGame()->UnloadGame();

	MenuManager->FlushNotifications();
	MenuManager->OpenMenu(EFlareMenu::MENU_Main);
}

void SFlareOrbitalMenu::OnExit()
{
	// TODO : Remove this + button once sectors can be opened with OnOpenSector
	MenuManager->OpenMenu(EFlareMenu::MENU_Main);
}

void SFlareOrbitalMenu::OnOpenSector(TSharedPtr<int32> Index)
{
	UFlareSimulatedSector* Sector = Game->GetGameWorld()->GetSectors()[*Index];

	AFlarePlayerController* PC = MenuManager->GetPC();
	if (PC)
	{
		Game->ActivateSector(PC, Sector);
	}
}

#undef LOCTEXT_NAMESPACE

<commit_msg>Removed orbit drawing for now<commit_after>
#include "../../Flare.h"
#include "FlareOrbitalMenu.h"
#include "../../Game/FlareGame.h"
#include "../../Player/FlareMenuManager.h"
#include "../../Player/FlarePlayerController.h"

#define LOCTEXT_NAMESPACE "FlareOrbitalMenu"

/*----------------------------------------------------
	Construct
----------------------------------------------------*/

void SFlareOrbitalMenu::Construct(const FArguments& InArgs)
{
	// Data
	MenuManager = InArgs._MenuManager;
	const FFlareStyleCatalog& Theme = FFlareStyleSet::GetDefaultTheme();
	Game = MenuManager->GetPC()->GetGame();

	// Build structure
	ChildSlot
	.HAlign(HAlign_Fill)
	.VAlign(VAlign_Fill)
	[
		SNew(SVerticalBox)

		+ SVerticalBox::Slot()
		.AutoHeight()
		.HAlign(HAlign_Fill)
		.VAlign(VAlign_Center)
		.Padding(Theme.ContentPadding)
		[
			SNew(SHorizontalBox)

			// Icon
			+ SHorizontalBox::Slot()
			.AutoWidth()
			[
				SNew(SImage).Image(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Orbit))
			]

			// Title
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.Padding(Theme.ContentPadding)
			[
				SNew(STextBlock)
				.TextStyle(&Theme.TitleFont)
				.Text(LOCTEXT("Orbital", "ORBITAL MAP"))
			]

			// Quit
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("Leaderboard", "Leaderboard"))
				.ToolTipText(LOCTEXT("LeaderboardInfo", "Take a look at the companies"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Leaderboard, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnOpenLeaderboard)
			]

			// Quit
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("SaveQuit", "Save and quit"))
				.ToolTipText(LOCTEXT("SaveQuitInfo", "Save the game and go back to the main menu"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Main, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnMainMenu)
			]

			// Close
			+ SHorizontalBox::Slot()
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.Padding(Theme.TitleButtonPadding)
			.AutoWidth()
			[
				SNew(SFlareRoundButton)
				.Text(LOCTEXT("Close", "Close"))
				.ToolTipText(LOCTEXT("CloseInfo", "Close the menu and go back to flying the ship"))
				.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_Exit, true))
				.OnClicked(this, &SFlareOrbitalMenu::OnExit)
			]
		]

		// Separator
		+ SVerticalBox::Slot()
		.AutoHeight()
		.Padding(FMargin(200, 20))
		[
			SNew(SImage).Image(&Theme.SeparatorBrush)
		]

		// Content
		+ SVerticalBox::Slot()
		.AutoHeight()
		.Padding(Theme.ContentPadding)
		[
			SAssignNew(SectorsBox, SHorizontalBox)
		]
	];

}

/*----------------------------------------------------
	Interaction
----------------------------------------------------*/

void SFlareOrbitalMenu::Setup()
{
	SetEnabled(false);
	SetVisibility(EVisibility::Hidden);
}

void SFlareOrbitalMenu::Enter()
{
	FLOG("SFlareOrbitalMenu::Enter");
	SetEnabled(true);
	SetVisibility(EVisibility::Visible);

	Game->DeactivateSector(MenuManager->GetPC());

	// Add sectors slots
	for (int32 SectorIndex = 0; SectorIndex < Game->GetGameWorld()->GetSectors().Num(); SectorIndex++)
	{
		TSharedPtr<int32> IndexPtr(new int32(SectorIndex));

		UFlareSimulatedSector* Sector = Game->GetGameWorld()->GetSectors()[SectorIndex];

		SectorsBox->AddSlot()
		[
			SNew(SFlareRoundButton)
			.Text(FText::FromString(Sector->GetSectorName()))
			.Icon(AFlareMenuManager::GetMenuIcon(EFlareMenu::MENU_None, true))
			.OnClicked(this, &SFlareOrbitalMenu::OnOpenSector, IndexPtr)
		];
	}
}

void SFlareOrbitalMenu::Exit()
{
	SetEnabled(false);
	SetVisibility(EVisibility::Hidden);

	SectorsBox->ClearChildren();
}

/*----------------------------------------------------
	Drawing
----------------------------------------------------*/

int32 SFlareOrbitalMenu::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
	//FVector2D PlanetCenter = ClippingRect.GetSize() / 2;

	//DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 200, 0, 200, 360);

	//DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 350, 45, 300, 225);

	//DrawOrbitPath(ClippingRect, OutDrawElements, LayerId, PlanetCenter, 350, -90, 300, 90);

	return SCompoundWidget::OnPaint(Args, AllottedGeometry, ClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}

void SFlareOrbitalMenu::DrawOrbitPath(const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
	FVector2D PlanetCenter, int32 RadiusA, int32 AngleA, int32 RadiusB, int32 AngleB) const
{
	// Setup initial data
	float InitialDistance = AngleB - AngleA;
	int32 InitialAngleA = AngleA;
	int32 DrawnDistance = 0;
	int32 DrawnSegments = 0;
	int32 MaxAngleInSegment = 90;

	// Compute initial points
	FVector2D PointA = GetPositionFromPolar(RadiusA, AngleA);
	FVector2D PointB = GetPositionFromPolar(RadiusB, AngleB);

	// Draw a series of segments until the path has been done.
	do
	{
		// Compute intermediate angles
		int32 CurrentAngleA = AngleA + DrawnSegments * MaxAngleInSegment;
		int32 CurrentAngleB = FMath::Min(CurrentAngleA + MaxAngleInSegment, AngleB);
		float CurrentAngleARad = FMath::DegreesToRadians(CurrentAngleA - InitialAngleA);
		float CurrentAngleBRad = FMath::DegreesToRadians(CurrentAngleB - InitialAngleA);

		// Polar equation of an ellipse : point A
		float CurrentRadiusA = (RadiusA * RadiusB) / FMath::Sqrt(
			FMath::Square(RadiusB * FMath::Cos(CurrentAngleARad)) +
			FMath::Square(RadiusA * FMath::Sin(CurrentAngleARad))
			);
		FVector2D CurrentPointA = GetPositionFromPolar(CurrentRadiusA, CurrentAngleA);;

		// Polar equation of an ellipse : point B
		float CurrentRadiusB = (RadiusA * RadiusB) / FMath::Sqrt(
			FMath::Square(RadiusB * FMath::Cos(CurrentAngleBRad)) +
			FMath::Square(RadiusA * FMath::Sin(CurrentAngleBRad))
			);
		FVector2D CurrentPointB = GetPositionFromPolar(CurrentRadiusB, CurrentAngleB);

		// Tangents vary depending on the angle and ellipse parameters
		float TangentSubdivisionRatio = ((CurrentAngleB - CurrentAngleA) / 90.0f);
		float TangentLength = TangentSubdivisionRatio * FMath::Sqrt(2);// *(1 + 0.3 * FMath::Sin((PI * (CurrentAngleA - InitialAngleA)) / 180));

		 // Compute intermediate tangents
		FVector2D CurrentTangentA = TangentLength * FVector2D(-CurrentPointA.Y, CurrentPointA.X);
		FVector2D CurrentTangentB = TangentLength * FVector2D(-CurrentPointB.Y, CurrentPointB.X);

		// Draw
		DrawOrbitSegment(ClippingRect, OutDrawElements, LayerId, PlanetCenter, CurrentPointA, CurrentTangentA, CurrentPointB, CurrentTangentB);
		DrawnDistance += (CurrentAngleB - CurrentAngleA);
		DrawnSegments++;

	} while (DrawnDistance < InitialDistance);
}

void SFlareOrbitalMenu::DrawOrbitSegment(const FSlateRect& ClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
	FVector2D PlanetCenter, FVector2D PointA, FVector2D TangentA, FVector2D PointB, FVector2D TangentB) const
{
	// Get the rendering parametrs
	const FFlareStyleCatalog& Theme = FFlareStyleSet::GetDefaultTheme();
	FLinearColor WireColor = Theme.NeutralColor;
	WireColor.A = Theme.DefaultAlpha;

	// Draw
	FSlateDrawElement::MakeDrawSpaceSpline(
		OutDrawElements,
		LayerId,
		PlanetCenter + PointA,
		TangentA,
		PlanetCenter + PointB,
		TangentB,
		ClippingRect,
		8,
		ESlateDrawEffect::None,
		WireColor
		);
}

inline FVector2D SFlareOrbitalMenu::GetPositionFromPolar(int32 Radius, int32 Angle) const
{
	float X, Y;
	FMath::PolarToCartesian(Radius, FMath::DegreesToRadians(Angle), X, Y);
	return FVector2D(X, Y);
}

/*----------------------------------------------------
	Callbacks
----------------------------------------------------*/

void SFlareOrbitalMenu::OnOpenLeaderboard()
{
	MenuManager->OpenMenu(EFlareMenu::MENU_Leaderboard);
}

void SFlareOrbitalMenu::OnMainMenu()
{
	AFlarePlayerController* PC = MenuManager->GetPC();

	PC->GetGame()->SaveGame(PC);
	PC->GetGame()->UnloadGame();

	MenuManager->FlushNotifications();
	MenuManager->OpenMenu(EFlareMenu::MENU_Main);
}

void SFlareOrbitalMenu::OnExit()
{
	// TODO : Remove this + button once sectors can be opened with OnOpenSector
	MenuManager->OpenMenu(EFlareMenu::MENU_Main);
}

void SFlareOrbitalMenu::OnOpenSector(TSharedPtr<int32> Index)
{
	UFlareSimulatedSector* Sector = Game->GetGameWorld()->GetSectors()[*Index];

	AFlarePlayerController* PC = MenuManager->GetPC();
	if (PC)
	{
		Game->ActivateSector(PC, Sector);
	}
}

#undef LOCTEXT_NAMESPACE

<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2013 the Urho3D project.
//
// 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 "Engine.h"
#include "FileSystem.h"
#include "Log.h"
#include "Main.h"
#include "ProcessUtils.h"
#include "ResourceCache.h"
#include "ResourceEvents.h"

#ifdef ENABLE_ANGELSCRIPT
#include "ScriptFile.h"
#include "Script.h"
#endif

#ifdef ENABLE_LUA
#include "LuaScript.h"
#endif

#include "Urho3DPlayer.h"

#include "DebugNew.h"

DEFINE_APPLICATION_MAIN(Urho3DPlayer);

Urho3DPlayer::Urho3DPlayer(Context* context) :
    Application(context)
{
}

void Urho3DPlayer::Setup()
{
    // On Android and iOS, read command line from a file as parameters can not otherwise be easily given
    #if defined(ANDROID) || defined(IOS)
    SharedPtr<File> commandFile(new File(context_, GetSubsystem<FileSystem>()->GetProgramDir() + "Data/CommandLine.txt",
        FILE_READ));
    String commandLine = commandFile->ReadLine();
    commandFile->Close();
    ParseArguments(commandLine, false);
    // Reparse engine startup parameters now
    engineParameters_ = Engine::ParseParameters(GetArguments());
    #endif

    // Check for script file name
    const Vector<String>& arguments = GetArguments();
    String scriptFileName;
    for (unsigned i = 0; i < arguments.Size(); ++i)
    {
        if (arguments[i][0] != '-')
        {
            scriptFileName_ = GetInternalPath(arguments[i]);
            break;
        }
    }

    // Show usage if not found
    if (scriptFileName_.Empty())
    {
        ErrorExit("Usage: Urho3DPlayer <scriptfile> [options]\n\n"
            "The script file should implement the function void Start() for initializing the "
            "application and subscribing to all necessary events, such as the frame update.\n"
            #ifndef WIN32
            "\nCommand line options:\n"
            "-x <res>     Horizontal resolution\n"
            "-y <res>     Vertical resolution\n"
            "-m <level>   Enable hardware multisampling\n"
            "-v           Enable vertical sync\n"
            "-t           Enable triple buffering\n"
            "-w           Start in windowed mode\n"
            "-s           Enable resizing when in windowed mode\n"
            "-q           Enable quiet mode which does not log to standard output stream\n"
            "-b <length>  Sound buffer length in milliseconds\n"
            "-r <freq>    Sound mixing frequency in Hz\n"
            "-p <paths>   Resource path(s) to use, separated by semicolons\n"
            "-log <level> Change the log level, valid 'level' values are 'debug', 'info', 'warning', 'error'\n"
            "-borderless  Borderless window mode\n"
            "-headless    Headless mode. No application window will be created\n"
            "-prepass     Use light pre-pass rendering\n"
            "-deferred    Use deferred rendering\n"
            "-lqshadows   Use low-quality (1-sample) shadow filtering\n"
            "-noshadows   Disable shadow rendering\n"
            "-nolimit     Disable frame limiter\n"
            "-nothreads   Disable worker threads\n"
            "-nosound     Disable sound output\n"
            "-noip        Disable sound mixing interpolation\n"
            "-sm2         Force SM2.0 rendering\n"
            #endif
        );
    }
}

void Urho3DPlayer::Start()
{
    String extension = GetExtension(scriptFileName_);
    if (extension != ".lua")
    {
#ifdef ENABLE_ANGELSCRIPT
        // Instantiate and register the AngelScript subsystem
        context_->RegisterSubsystem(new Script(context_));

        // Hold a shared pointer to the script file to make sure it is not unloaded during runtime
        scriptFile_ = GetSubsystem<ResourceCache>()->GetResource<ScriptFile>(scriptFileName_);

        // If script loading is successful, proceed to main loop
        if (scriptFile_ && scriptFile_->Execute("void Start()"))
        {
            // Subscribe to script's reload event to allow live-reload of the application
            SubscribeToEvent(scriptFile_, E_RELOADSTARTED, HANDLER(Urho3DPlayer, HandleScriptReloadStarted));
            SubscribeToEvent(scriptFile_, E_RELOADFINISHED, HANDLER(Urho3DPlayer, HandleScriptReloadFinished));
            SubscribeToEvent(scriptFile_, E_RELOADFAILED, HANDLER(Urho3DPlayer, HandleScriptReloadFailed));
            return;
        }
#else
        ErrorExit("AngelScript is not enabled!");
#endif
    }
    else
    {
#ifdef ENABLE_LUA
        // Instantiate and register the Lua script subsystem
        LuaScript* luaScript = new LuaScript(context_);
        context_->RegisterSubsystem(luaScript);

        // If script loading is successful, proceed to main loop
        if (luaScript->ExecuteFile(scriptFileName_))
        {
            luaScript->ExecuteFunction("Start");
            return;
        }
#else
        ErrorExit("Lua is not enabled!");
#endif
    }

    // The script was not successfully loaded. Show the last error message and do not run the main loop
    ErrorExit();
}

void Urho3DPlayer::Stop()
{
#ifdef ENABLE_ANGELSCRIPT
    if (scriptFile_)
    {
        // Execute the optional stop function
        if (scriptFile_->GetFunction("void Stop()"))
            scriptFile_->Execute("void Stop()");
    }
#else
    if (false)
    {
    }
#endif

#ifdef ENABLE_LUA
    else
    {
        LuaScript* luaScript = GetSubsystem<LuaScript>();
        if (luaScript && luaScript->GetFunction("Stop", true))
            luaScript->ExecuteFunction("Stop");
    }
#endif
}

void Urho3DPlayer::HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    if (scriptFile_->GetFunction("void Stop()"))
        scriptFile_->Execute("void Stop()");
#endif
}

void Urho3DPlayer::HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    // Restart the script application after reload
    if (!scriptFile_->Execute("void Start()"))
    {
        scriptFile_.Reset();
        ErrorExit();
    }
#endif
}

void Urho3DPlayer::HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    scriptFile_.Reset();
    ErrorExit();
#endif
}
<commit_msg>Return in Urho3DPlayer if the script language is not supported to prevent showing two error dialog boxes.<commit_after>//
// Copyright (c) 2008-2013 the Urho3D project.
//
// 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 "Engine.h"
#include "FileSystem.h"
#include "Log.h"
#include "Main.h"
#include "ProcessUtils.h"
#include "ResourceCache.h"
#include "ResourceEvents.h"

#ifdef ENABLE_ANGELSCRIPT
#include "ScriptFile.h"
#include "Script.h"
#endif

#ifdef ENABLE_LUA
#include "LuaScript.h"
#endif

#include "Urho3DPlayer.h"

#include "DebugNew.h"

DEFINE_APPLICATION_MAIN(Urho3DPlayer);

Urho3DPlayer::Urho3DPlayer(Context* context) :
    Application(context)
{
}

void Urho3DPlayer::Setup()
{
    // On Android and iOS, read command line from a file as parameters can not otherwise be easily given
    #if defined(ANDROID) || defined(IOS)
    SharedPtr<File> commandFile(new File(context_, GetSubsystem<FileSystem>()->GetProgramDir() + "Data/CommandLine.txt",
        FILE_READ));
    String commandLine = commandFile->ReadLine();
    commandFile->Close();
    ParseArguments(commandLine, false);
    // Reparse engine startup parameters now
    engineParameters_ = Engine::ParseParameters(GetArguments());
    #endif

    // Check for script file name
    const Vector<String>& arguments = GetArguments();
    String scriptFileName;
    for (unsigned i = 0; i < arguments.Size(); ++i)
    {
        if (arguments[i][0] != '-')
        {
            scriptFileName_ = GetInternalPath(arguments[i]);
            break;
        }
    }

    // Show usage if not found
    if (scriptFileName_.Empty())
    {
        ErrorExit("Usage: Urho3DPlayer <scriptfile> [options]\n\n"
            "The script file should implement the function void Start() for initializing the "
            "application and subscribing to all necessary events, such as the frame update.\n"
            #ifndef WIN32
            "\nCommand line options:\n"
            "-x <res>     Horizontal resolution\n"
            "-y <res>     Vertical resolution\n"
            "-m <level>   Enable hardware multisampling\n"
            "-v           Enable vertical sync\n"
            "-t           Enable triple buffering\n"
            "-w           Start in windowed mode\n"
            "-s           Enable resizing when in windowed mode\n"
            "-q           Enable quiet mode which does not log to standard output stream\n"
            "-b <length>  Sound buffer length in milliseconds\n"
            "-r <freq>    Sound mixing frequency in Hz\n"
            "-p <paths>   Resource path(s) to use, separated by semicolons\n"
            "-log <level> Change the log level, valid 'level' values are 'debug', 'info', 'warning', 'error'\n"
            "-borderless  Borderless window mode\n"
            "-headless    Headless mode. No application window will be created\n"
            "-prepass     Use light pre-pass rendering\n"
            "-deferred    Use deferred rendering\n"
            "-lqshadows   Use low-quality (1-sample) shadow filtering\n"
            "-noshadows   Disable shadow rendering\n"
            "-nolimit     Disable frame limiter\n"
            "-nothreads   Disable worker threads\n"
            "-nosound     Disable sound output\n"
            "-noip        Disable sound mixing interpolation\n"
            "-sm2         Force SM2.0 rendering\n"
            #endif
        );
    }
}

void Urho3DPlayer::Start()
{
    String extension = GetExtension(scriptFileName_);
    if (extension != ".lua")
    {
#ifdef ENABLE_ANGELSCRIPT
        // Instantiate and register the AngelScript subsystem
        context_->RegisterSubsystem(new Script(context_));

        // Hold a shared pointer to the script file to make sure it is not unloaded during runtime
        scriptFile_ = GetSubsystem<ResourceCache>()->GetResource<ScriptFile>(scriptFileName_);

        // If script loading is successful, proceed to main loop
        if (scriptFile_ && scriptFile_->Execute("void Start()"))
        {
            // Subscribe to script's reload event to allow live-reload of the application
            SubscribeToEvent(scriptFile_, E_RELOADSTARTED, HANDLER(Urho3DPlayer, HandleScriptReloadStarted));
            SubscribeToEvent(scriptFile_, E_RELOADFINISHED, HANDLER(Urho3DPlayer, HandleScriptReloadFinished));
            SubscribeToEvent(scriptFile_, E_RELOADFAILED, HANDLER(Urho3DPlayer, HandleScriptReloadFailed));
            return;
        }
#else
        ErrorExit("AngelScript is not enabled!");
        return;
#endif
    }
    else
    {
#ifdef ENABLE_LUA
        // Instantiate and register the Lua script subsystem
        LuaScript* luaScript = new LuaScript(context_);
        context_->RegisterSubsystem(luaScript);

        // If script loading is successful, proceed to main loop
        if (luaScript->ExecuteFile(scriptFileName_))
        {
            luaScript->ExecuteFunction("Start");
            return;
        }
#else
        ErrorExit("Lua is not enabled!");
        return;
#endif
    }

    // The script was not successfully loaded. Show the last error message and do not run the main loop
    ErrorExit();
}

void Urho3DPlayer::Stop()
{
#ifdef ENABLE_ANGELSCRIPT
    if (scriptFile_)
    {
        // Execute the optional stop function
        if (scriptFile_->GetFunction("void Stop()"))
            scriptFile_->Execute("void Stop()");
    }
#else
    if (false)
    {
    }
#endif

#ifdef ENABLE_LUA
    else
    {
        LuaScript* luaScript = GetSubsystem<LuaScript>();
        if (luaScript && luaScript->GetFunction("Stop", true))
            luaScript->ExecuteFunction("Stop");
    }
#endif
}

void Urho3DPlayer::HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    if (scriptFile_->GetFunction("void Stop()"))
        scriptFile_->Execute("void Stop()");
#endif
}

void Urho3DPlayer::HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    // Restart the script application after reload
    if (!scriptFile_->Execute("void Start()"))
    {
        scriptFile_.Reset();
        ErrorExit();
    }
#endif
}

void Urho3DPlayer::HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData)
{
#ifdef ENABLE_ANGELSCRIPT
    scriptFile_.Reset();
    ErrorExit();
#endif
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * 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
 *
 *****************************************************************************/
//$Id$

#include <boost/python.hpp>

#include <mapnik/text_placements.hpp>
#include "mapnik_enumeration.hpp"
#include <mapnik/expression_string.hpp>

using namespace mapnik;
//using mapnik::color;
//using mapnik::text_symbolizer;
//using mapnik::expr_node;
//using mapnik::expression_ptr;
//using mapnik::to_expression_string;

namespace {
using namespace boost::python;

tuple get_displacement(text_symbolizer_properties const& t)
{
    return boost::python::make_tuple(t.displacement.first, t.displacement.second);
}

void set_displacement(text_symbolizer_properties &t, boost::python::tuple arg)
{
    double x = extract<double>(arg[0]);
    double y = extract<double>(arg[0]);
    t.displacement = std::make_pair(x, y);
}

}

void export_text_placement()
{
    using namespace boost::python;

    enumeration_<label_placement_e>("label_placement")
        .value("LINE_PLACEMENT",LINE_PLACEMENT)
        .value("POINT_PLACEMENT",POINT_PLACEMENT)
        .value("VERTEX_PLACEMENT",VERTEX_PLACEMENT)
        .value("INTERIOR_PLACEMENT",INTERIOR_PLACEMENT)
        ;
    enumeration_<vertical_alignment_e>("vertical_alignment")
        .value("TOP",V_TOP)
        .value("MIDDLE",V_MIDDLE)
        .value("BOTTOM",V_BOTTOM)
        .value("AUTO",V_AUTO)
        ;

    enumeration_<horizontal_alignment_e>("horizontal_alignment")
        .value("LEFT",H_LEFT)
        .value("MIDDLE",H_MIDDLE)
        .value("RIGHT",H_RIGHT)
        .value("AUTO",H_AUTO)
        ;

    enumeration_<justify_alignment_e>("justify_alignment")
        .value("LEFT",J_LEFT)
        .value("MIDDLE",J_MIDDLE)
        .value("RIGHT",J_RIGHT)
        ;

    enumeration_<text_transform_e>("text_transform")
        .value("NONE",NONE)
        .value("UPPERCASE",UPPERCASE)
        .value("LOWERCASE",LOWERCASE)
        .value("CAPITALIZE",CAPITALIZE)
        ;

    class_<text_symbolizer_properties>("TextSymbolizerProperties")
            .def_readwrite("orientation", &text_symbolizer_properties::orientation)
            .add_property("displacement",
                          &get_displacement,
                          &set_displacement)
            .def_readwrite("label_placement", &text_symbolizer_properties::label_placement)
            .def_readwrite("horizontal_alignment", &text_symbolizer_properties::halign)
            .def_readwrite("justify_alignment", &text_symbolizer_properties::jalign)
            .def_readwrite("vertical_alignment", &text_symbolizer_properties::valign)
            .def_readwrite("label_spacing", &text_symbolizer_properties::label_spacing)
            .def_readwrite("label_position_tolerance", &text_symbolizer_properties::label_position_tolerance)
            .def_readwrite("avoid_edges", &text_symbolizer_properties::avoid_edges)
            .def_readwrite("minimum_distance", &text_symbolizer_properties::minimum_distance)
            .def_readwrite("minimum_padding", &text_symbolizer_properties::minimum_padding)
            .def_readwrite("minimum_path_length", &text_symbolizer_properties::minimum_path_length)
            .def_readwrite("maximum_angle_char_delta", &text_symbolizer_properties::max_char_angle_delta)
            .def_readwrite("force_odd_labels", &text_symbolizer_properties::force_odd_labels)
            .def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap)
            .def_readwrite("text_ratio", &text_symbolizer_properties::text_ratio)
            .def_readwrite("wrap_width", &text_symbolizer_properties::wrap_width)
            /* TODO: text_processor */
            /* from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python.*/
            ;
    class_<char_properties>("CharProperties")
            .def_readwrite("face_name", &char_properties::face_name)
            .def_readwrite("fontset", &char_properties::fontset)
            .def_readwrite("text_size", &char_properties::text_size)
            .def_readwrite("character_spacing", &char_properties::character_spacing)
            .def_readwrite("line_spacing", &char_properties::line_spacing)
            .def_readwrite("text_opacity", &char_properties::text_opacity)
            .def_readwrite("wrap_char", &char_properties::wrap_char)
            .def_readwrite("wrap_before", &char_properties::wrap_before)
            .def_readwrite("text_transform", &char_properties::text_transform)
            .def_readwrite("fill", &char_properties::fill)
            .def_readwrite("halo_fill", &char_properties::halo_fill)
            .def_readwrite("halo_radius", &char_properties::halo_radius)
            ;
}
<commit_msg>+ validate input tuple length + fix index in extract<double><commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * 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
 *
 *****************************************************************************/
//$Id$

#include <boost/python.hpp>

#include <mapnik/text_placements.hpp>
#include "mapnik_enumeration.hpp"
#include <mapnik/expression_string.hpp>

using namespace mapnik;
//using mapnik::color;
//using mapnik::text_symbolizer;
//using mapnik::expr_node;
//using mapnik::expression_ptr;
//using mapnik::to_expression_string;

namespace {
using namespace boost::python;

tuple get_displacement(text_symbolizer_properties const& t)
{
    return boost::python::make_tuple(t.displacement.first, t.displacement.second);
}

void set_displacement(text_symbolizer_properties &t, boost::python::tuple arg)
{
    if (len(arg) != 2)
    {
        PyErr_SetObject(PyExc_ValueError,
                        ("expected 2-item tuple in call to set_displacement; got %s"
                         % arg).ptr()
            );
        throw_error_already_set();
    }

    double x = extract<double>(arg[0]);
    double y = extract<double>(arg[1]);
    t.displacement = std::make_pair(x, y);
}

}

void export_text_placement()
{
    using namespace boost::python;

    enumeration_<label_placement_e>("label_placement")
        .value("LINE_PLACEMENT",LINE_PLACEMENT)
        .value("POINT_PLACEMENT",POINT_PLACEMENT)
        .value("VERTEX_PLACEMENT",VERTEX_PLACEMENT)
        .value("INTERIOR_PLACEMENT",INTERIOR_PLACEMENT)
        ;
    enumeration_<vertical_alignment_e>("vertical_alignment")
        .value("TOP",V_TOP)
        .value("MIDDLE",V_MIDDLE)
        .value("BOTTOM",V_BOTTOM)
        .value("AUTO",V_AUTO)
        ;

    enumeration_<horizontal_alignment_e>("horizontal_alignment")
        .value("LEFT",H_LEFT)
        .value("MIDDLE",H_MIDDLE)
        .value("RIGHT",H_RIGHT)
        .value("AUTO",H_AUTO)
        ;

    enumeration_<justify_alignment_e>("justify_alignment")
        .value("LEFT",J_LEFT)
        .value("MIDDLE",J_MIDDLE)
        .value("RIGHT",J_RIGHT)
        ;

    enumeration_<text_transform_e>("text_transform")
        .value("NONE",NONE)
        .value("UPPERCASE",UPPERCASE)
        .value("LOWERCASE",LOWERCASE)
        .value("CAPITALIZE",CAPITALIZE)
        ;

    class_<text_symbolizer_properties>("TextSymbolizerProperties")
            .def_readwrite("orientation", &text_symbolizer_properties::orientation)
            .add_property("displacement",
                          &get_displacement,
                          &set_displacement)
            .def_readwrite("label_placement", &text_symbolizer_properties::label_placement)
            .def_readwrite("horizontal_alignment", &text_symbolizer_properties::halign)
            .def_readwrite("justify_alignment", &text_symbolizer_properties::jalign)
            .def_readwrite("vertical_alignment", &text_symbolizer_properties::valign)
            .def_readwrite("label_spacing", &text_symbolizer_properties::label_spacing)
            .def_readwrite("label_position_tolerance", &text_symbolizer_properties::label_position_tolerance)
            .def_readwrite("avoid_edges", &text_symbolizer_properties::avoid_edges)
            .def_readwrite("minimum_distance", &text_symbolizer_properties::minimum_distance)
            .def_readwrite("minimum_padding", &text_symbolizer_properties::minimum_padding)
            .def_readwrite("minimum_path_length", &text_symbolizer_properties::minimum_path_length)
            .def_readwrite("maximum_angle_char_delta", &text_symbolizer_properties::max_char_angle_delta)
            .def_readwrite("force_odd_labels", &text_symbolizer_properties::force_odd_labels)
            .def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap)
            .def_readwrite("text_ratio", &text_symbolizer_properties::text_ratio)
            .def_readwrite("wrap_width", &text_symbolizer_properties::wrap_width)
            /* TODO: text_processor */
            /* from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python.*/
            ;
    class_<char_properties>("CharProperties")
            .def_readwrite("face_name", &char_properties::face_name)
            .def_readwrite("fontset", &char_properties::fontset)
            .def_readwrite("text_size", &char_properties::text_size)
            .def_readwrite("character_spacing", &char_properties::character_spacing)
            .def_readwrite("line_spacing", &char_properties::line_spacing)
            .def_readwrite("text_opacity", &char_properties::text_opacity)
            .def_readwrite("wrap_char", &char_properties::wrap_char)
            .def_readwrite("wrap_before", &char_properties::wrap_before)
            .def_readwrite("text_transform", &char_properties::text_transform)
            .def_readwrite("fill", &char_properties::fill)
            .def_readwrite("halo_fill", &char_properties::halo_fill)
            .def_readwrite("halo_radius", &char_properties::halo_radius)
            ;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "grpc_client.h"
#include "paddle/framework/threadpool.h"
namespace paddle {
namespace operators {
namespace detail {

bool RPCClient::AsyncSendVariable(const std::string& ep,
                                  const platform::DeviceContext& ctx,
                                  const framework::Scope& scope,
                                  const std::string& var_name,
                                  int64_t time_out) {
  const platform::DeviceContext* p_ctx = &ctx;
  const std::string ep_val = ep;
  const std::string var_name_val = var_name;
  const framework::Scope* p_scope = &scope;
  const auto ch = GetChannel(ep_val);

  framework::Async([var_name_val, p_ctx, ep_val, p_scope, time_out, ch, this] {
    auto* var = p_scope->FindVar(var_name_val);
    sendrecv::VariableMessage req;
    SerializeToMessage(var_name_val, var, *p_ctx, &req);

    // varhandle
    VarHandle var_h;
    var_h.ep = ep_val;
    var_h.scope = p_scope;
    var_h.name = var_name_val;
    var_h.ctx = p_ctx;

    // stub context
    SendProcessor* s = new SendProcessor(ch);
    s->Prepare(var_h, time_out);
    s->response_call_back_ = NULL;

    auto rpc = s->stub_->AsyncSendVariable(s->context_.get(), req, &cq_);
    rpc->Finish(&s->reply_, &s->status_, (void*)s);
  });

  req_count_++;

  return true;
}

void ProcGetResponse(const VarHandle& var_h,
                     const sendrecv::VariableMessage& ret_msg) {
  auto* outvar = var_h.scope->FindVar(var_h.name);
  DeserializeFromMessage(ret_msg, *var_h.ctx, outvar);
}

bool RPCClient::AsyncGetVariable(const std::string& ep,
                                 const platform::DeviceContext& ctx,
                                 const framework::Scope& scope,
                                 const std::string& var_name,
                                 int64_t time_out) {
  const platform::DeviceContext* p_ctx = &ctx;
  const std::string ep_val = ep;
  const std::string var_name_val = var_name;
  const framework::Scope* p_scope = &scope;
  const auto ch = GetChannel(ep_val);

  framework::Async([var_name_val, ep_val, p_scope, p_ctx, time_out, ch, this] {
    sendrecv::VariableMessage req;
    req.set_varname(var_name_val);

    // varhandle
    VarHandle var_h;
    var_h.ep = ep_val;
    var_h.scope = p_scope;
    var_h.name = var_name_val;
    var_h.ctx = p_ctx;

    // stub context
    GetProcessor* s = new GetProcessor(ch);
    s->Prepare(var_h, time_out);
    s->response_call_back_ = ProcGetResponse;

    auto rpc = s->stub_->AsyncGetVariable(s->context_.get(), req, &cq_);
    rpc->Finish(&s->reply_, &s->status_, (void*)s);
  });

  req_count_++;

  return true;
}

bool RPCClient::Wait() {
  if (req_count_ <= 0) {
    return true;
  }

  std::vector<bool> a(req_count_);
  std::vector<std::future<void>> waits(req_count_);

  for (int i = 0; i < req_count_; i++) {
    waits[i] = framework::Async([i, &a, this] { a[i] = Proceed(); });
  }

  for (int i = 0; i < req_count_; i++) {
    waits[i].wait();
  }

  int last_req_count = req_count_;
  req_count_ = 0;

  for (int i = 0; i < last_req_count; i++) {
    if (!a[i]) {
      return false;
    }
  }

  return true;
}

bool RPCClient::Proceed() {
  void* tag = NULL;
  bool ok = false;

  // request counts.
  if (!cq_.Next(&tag, &ok)) {
    LOG(ERROR) << "Get meets CompletionQueue error";
    return false;
  }

  GPR_ASSERT(ok);
  PADDLE_ENFORCE(tag);

  // TODO(gongwb): add more retries.
  ClientBase* c = static_cast<ClientBase*>(tag);
  if (!c->status_.ok()) {
    LOG(ERROR) << "proc param error:" << c->var_h_.String()
               << " grpc error:" << c->status_.error_message();
    delete c;
    return false;
  }

  c->Process();
  delete c;
  return true;
}

std::shared_ptr<grpc::Channel> RPCClient::GetChannel(const std::string& ep) {
  auto it = channels_.find(ep);
  if (it != channels_.end()) {
    return it->second;
  }

  grpc::ChannelArguments args;
  args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
  args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());

  auto ch = std::shared_ptr<grpc::Channel>(
      grpc::CreateCustomChannel(ep, grpc::InsecureChannelCredentials(), args));

  channels_[ep] = ch;
  return ch;
}

}  // namespace detail
}  // namespace operators
}  // namespace paddle
<commit_msg>Fix send op data race<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "grpc_client.h"
#include "paddle/framework/threadpool.h"
namespace paddle {
namespace operators {
namespace detail {

bool RPCClient::AsyncSendVariable(const std::string& ep,
                                  const platform::DeviceContext& ctx,
                                  const framework::Scope& scope,
                                  const std::string& var_name,
                                  int64_t time_out) {
  const platform::DeviceContext* p_ctx = &ctx;
  const std::string ep_val = ep;
  const std::string var_name_val = var_name;
  const framework::Scope* p_scope = &scope;
  const auto ch = GetChannel(ep_val);

  framework::Async([var_name_val, p_ctx, ep_val, p_scope, time_out, ch, this] {
    auto* var = p_scope->FindVar(var_name_val);
    sendrecv::VariableMessage req;
    SerializeToMessage(var_name_val, var, *p_ctx, &req);

    // varhandle
    VarHandle var_h;
    var_h.ep = ep_val;
    var_h.scope = p_scope;
    var_h.name = var_name_val;
    var_h.ctx = p_ctx;

    // stub context
    SendProcessor* s = new SendProcessor(ch);
    s->Prepare(var_h, time_out);
    s->response_call_back_ = NULL;

    auto rpc = s->stub_->AsyncSendVariable(s->context_.get(), req, &cq_);
    rpc->Finish(&s->reply_, &s->status_, (void*)s);
  });

  req_count_++;

  return true;
}

void ProcGetResponse(const VarHandle& var_h,
                     const sendrecv::VariableMessage& ret_msg) {
  auto* outvar = var_h.scope->FindVar(var_h.name);
  DeserializeFromMessage(ret_msg, *var_h.ctx, outvar);
}

bool RPCClient::AsyncGetVariable(const std::string& ep,
                                 const platform::DeviceContext& ctx,
                                 const framework::Scope& scope,
                                 const std::string& var_name,
                                 int64_t time_out) {
  const platform::DeviceContext* p_ctx = &ctx;
  const std::string ep_val = ep;
  const std::string var_name_val = var_name;
  const framework::Scope* p_scope = &scope;
  const auto ch = GetChannel(ep_val);

  framework::Async([var_name_val, ep_val, p_scope, p_ctx, time_out, ch, this] {
    sendrecv::VariableMessage req;
    req.set_varname(var_name_val);

    // varhandle
    VarHandle var_h;
    var_h.ep = ep_val;
    var_h.scope = p_scope;
    var_h.name = var_name_val;
    var_h.ctx = p_ctx;

    // stub context
    GetProcessor* s = new GetProcessor(ch);
    s->Prepare(var_h, time_out);
    s->response_call_back_ = ProcGetResponse;

    auto rpc = s->stub_->AsyncGetVariable(s->context_.get(), req, &cq_);
    rpc->Finish(&s->reply_, &s->status_, (void*)s);
  });

  req_count_++;

  return true;
}

bool RPCClient::Wait() {
  if (req_count_ <= 0) {
    return true;
  }

  bool a[req_count_];
  std::vector<std::future<void>> waits(req_count_);

  for (int i = 0; i < req_count_; i++) {
    waits[i] = framework::Async([i, &a, this] { a[i] = Proceed(); });
  }

  for (int i = 0; i < req_count_; i++) {
    waits[i].wait();
  }

  int last_req_count = req_count_;
  req_count_ = 0;

  for (int i = 0; i < last_req_count; i++) {
    if (!a[i]) {
      return false;
    }
  }

  return true;
}

bool RPCClient::Proceed() {
  void* tag = NULL;
  bool ok = false;

  // request counts.
  if (!cq_.Next(&tag, &ok)) {
    LOG(ERROR) << "Get meets CompletionQueue error";
    return false;
  }

  GPR_ASSERT(ok);
  PADDLE_ENFORCE(tag);

  // TODO(gongwb): add more retries.
  ClientBase* c = static_cast<ClientBase*>(tag);
  if (!c->status_.ok()) {
    LOG(ERROR) << "proc param error:" << c->var_h_.String()
               << " grpc error:" << c->status_.error_message();
    delete c;
    return false;
  }

  c->Process();
  delete c;
  return true;
}

std::shared_ptr<grpc::Channel> RPCClient::GetChannel(const std::string& ep) {
  auto it = channels_.find(ep);
  if (it != channels_.end()) {
    return it->second;
  }

  grpc::ChannelArguments args;
  args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
  args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());

  auto ch = std::shared_ptr<grpc::Channel>(
      grpc::CreateCustomChannel(ep, grpc::InsecureChannelCredentials(), args));

  channels_[ep] = ch;
  return ch;
}

}  // namespace detail
}  // namespace operators
}  // namespace paddle
<|endoftext|>