<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));
        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 final_null;
          If check_count{codegen, codegen->CreateICmpEQ(count.GetValue(),
                                                        codegen.Const64(0))};
          {
            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}];
        codegen::Value sum = vals[{source, ExpressionType::AGGREGATE_SUM}];
        codegen::Value casted_sum = sum.CastTo(codegen, count.GetType());

        codegen::Value final_val =
            casted_sum.Div(codegen, count, Value::OnError::Ignore);
        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));
        LOG_ERROR("%s", message.c_str());
        throw Exception{EXCEPTION_TYPE_UNKNOWN_TYPE, message};
      }
    }
  }
}

}  // namespace codegen
}  // namespace peloton
<commit_msg>More compilation problems<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[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 final_null;
          If check_count{codegen, codegen->CreateICmpEQ(count.GetValue(),
                                                        codegen.Const64(0))};
          {
            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}];
        codegen::Value sum = vals[{source, ExpressionType::AGGREGATE_SUM}];
        codegen::Value casted_sum = sum.CastTo(codegen, count.GetType());

        codegen::Value final_val =
            casted_sum.Div(codegen, count, Value::OnError::Ignore);
        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>#include <string>

#include <cppunit/extensions/HelperMacros.h>

#include "ecru.h"

using namespace std;

class EcruTest : public CPPUNIT_NS::TestFixture
{
	private:
		CPPUNIT_TEST_SUITE( EcruTest );
		CPPUNIT_TEST( testStripString );
		CPPUNIT_TEST( testStripNewLines );
		CPPUNIT_TEST_SUITE_END();

	public:
		void testStripString();
		void testStripNewLines();
};

CPPUNIT_TEST_SUITE_REGISTRATION( EcruTest );

void EcruTest::testStripString()
{
	// typical usage
	string unstripped = "   somestr ";
	string stripped = ecru::stripString(unstripped);

	CPPUNIT_ASSERT_EQUAL(unstripped.size(), stripped.size() + 4);
	CPPUNIT_ASSERT(stripped == "somestr");

	// find out what's going on if we pass empty string
	string empty = ecru::stripString("");

	CPPUNIT_ASSERT(empty == "");

	// check if it doesn't modify a string that doesn't need
	// to be stripped
	string alreadyStripped;
	string doubleStrip = ecru::stripString(alreadyStripped);

	CPPUNIT_ASSERT(doubleStrip == alreadyStripped);
}

void EcruTest::testStripNewLines()
{
	// typical usage
	string stringWithNewLines = "hello\nhow are\nyou doing\n";
	string stripped = ecru::stripNewLines(stringWithNewLines);

	CPPUNIT_ASSERT(stripped.find("\n") == string::npos);

	// empty
	CPPUNIT_ASSERT("" == ecru::stripNewLines(""));

	// without new lines
	CPPUNIT_ASSERT("foo" == ecru::stripNewLines("foo"));
}
<commit_msg>Add a test for executeCommand().<commit_after>#include <string>

#include <cppunit/extensions/HelperMacros.h>

#include "ecru.h"

using namespace std;

class EcruTest : public CPPUNIT_NS::TestFixture
{
	private:
		CPPUNIT_TEST_SUITE( EcruTest );
		CPPUNIT_TEST( testStripString );
		CPPUNIT_TEST( testStripNewLines );
		CPPUNIT_TEST( testExecuteCommandWithValidCommand );
		CPPUNIT_TEST_SUITE_END();

	public:
		void testStripString();
		void testStripNewLines();
		void testExecuteCommandWithValidCommand();
};

CPPUNIT_TEST_SUITE_REGISTRATION( EcruTest );

void EcruTest::testStripString()
{
	// typical usage
	string unstripped = "   somestr ";
	string stripped = ecru::stripString(unstripped);

	CPPUNIT_ASSERT_EQUAL(unstripped.size(), stripped.size() + 4);
	CPPUNIT_ASSERT(stripped == "somestr");

	// find out what's going on if we pass empty string
	string empty = ecru::stripString("");

	CPPUNIT_ASSERT(empty == "");

	// check if it doesn't modify a string that doesn't need
	// to be stripped
	string alreadyStripped;
	string doubleStrip = ecru::stripString(alreadyStripped);

	CPPUNIT_ASSERT(doubleStrip == alreadyStripped);
}

void EcruTest::testStripNewLines()
{
	// typical usage
	string stringWithNewLines = "hello\nhow are\nyou doing\n";
	string stripped = ecru::stripNewLines(stringWithNewLines);

	CPPUNIT_ASSERT(stripped.find("\n") == string::npos);

	// empty
	CPPUNIT_ASSERT("" == ecru::stripNewLines(""));

	// without new lines
	CPPUNIT_ASSERT("foo" == ecru::stripNewLines("foo"));
}

void EcruTest::testExecuteCommandWithValidCommand()
{
	vector<string> args;

	args.push_back("-a");

	int status = ecru::executeCommand("/usr/bin/uname", args);

	CPPUNIT_ASSERT(status == 0);
}
<|endoftext|>


<commit_before>#include "Game.h"
#include "TextureManager.h"
#include "Player.h"
#include "Enemy.h"
#include "InputHandler.h"
#include "MenuState.h"
#include "PlayState.h"

//definition for static instance
Game* Game::s_pInstance = 0;

bool Game::init(const char *title, int xpos, int ypos, int width, int height, bool fullscreen)
{
	int flags = 0;
	if (fullscreen)
	{
		flags = SDL_WINDOW_FULLSCREEN;
	}

	//attempt to initialize SDL
	if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
	{
		std::cout << "SDL init success\n";
		//init the window
		m_pWindow = SDL_CreateWindow(title, xpos, ypos, width, height, flags);

		if (m_pWindow != 0)	//window init success
		{
			std::cout << "Window creation success\n";
			m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);

			if (m_pRenderer != 0) //renderer init success
			{
				std::cout << "renderer init success\n";
				SDL_SetRenderDrawColor(m_pRenderer, 255, 0, 0, 255);
			}
			else
			{
				std::cout << "renderer init failed\n";
				return false;	//renderer init fail
			}
		}
		else
		{
			std::cout << "window init fail\n";
			return false;	//window init fail
		}
	}
	else
	{
		std::cout << "SDL init fail\n";
		return false;	//SDL init fail
	}

	//initialise joysticks
	TheInputHandler::Instance()->initialiseJoysticks();

	std::cout << "init success\n";

	//load TextureManager
	if (!TheTextureManager::Instance()->load("assets/animate-alpha.png", "animate", m_pRenderer))
	{
		return false;
	}

	//creating and pushing objects
	m_gameObjects.push_back(new Player(new LoaderParams(100, 100, 128, 82, "animate")));
	m_gameObjects.push_back(new Enemy(new LoaderParams(300, 300, 128, 82, "animate")));

	m_bRunning = true;	//everything inited successfully, start the main loop

	//load MENU state
	m_pGameStateMachine = new GameStateMachine();
	m_pGameStateMachine->changeState(new MenuState());

	return true;
}

bool Game::running()
{
	return m_bRunning;
}

void Game::handleEvents()
{
	//waits and listens for a quit event
	TheInputHandler::Instance()->update();

	if (TheInputHandler::Instance()->isKeyDown(SDL_SCANCODE_RETURN))
	{
		m_pGameStateMachine->changeState(new PlayState());
	}
}

void Game::update()
{
	//loop through and update our objects
	for (std::vector<GameObject*>::size_type i = 0; i != m_gameObjects.size(); ++i)
	{
		m_gameObjects[i]->update();
	}
}

void Game::render()
{
	SDL_RenderClear(m_pRenderer); //clear the renderer to the draw color

	//loop through our objects and draw them
	for (std::vector<GameObject*>::size_type i = 0; i != m_gameObjects.size(); i++)
	{
		m_gameObjects[i]->draw();
	}

	SDL_RenderPresent(m_pRenderer);	//draw to the screen
}

void Game::clean()
{
	std::cout << "cleaning game\n";

	//close the joysticks
	TheInputHandler::Instance()->clean();

	SDL_DestroyWindow(m_pWindow);
	SDL_DestroyRenderer(m_pRenderer);
	SDL_Quit();
}

void Game::quit()
{
	m_bRunning = false;
}<commit_msg>Game now uses GameStateMachine's update and render function<commit_after>#include "Game.h"
#include "TextureManager.h"
#include "Player.h"
#include "Enemy.h"
#include "InputHandler.h"
#include "MenuState.h"
#include "PlayState.h"

//definition for static instance
Game* Game::s_pInstance = 0;

bool Game::init(const char *title, int xpos, int ypos, int width, int height, bool fullscreen)
{
	int flags = 0;
	if (fullscreen)
	{
		flags = SDL_WINDOW_FULLSCREEN;
	}

	//attempt to initialize SDL
	if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
	{
		std::cout << "SDL init success\n";
		//init the window
		m_pWindow = SDL_CreateWindow(title, xpos, ypos, width, height, flags);

		if (m_pWindow != 0)	//window init success
		{
			std::cout << "Window creation success\n";
			m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);

			if (m_pRenderer != 0) //renderer init success
			{
				std::cout << "renderer init success\n";
				SDL_SetRenderDrawColor(m_pRenderer, 255, 0, 0, 255);
			}
			else
			{
				std::cout << "renderer init failed\n";
				return false;	//renderer init fail
			}
		}
		else
		{
			std::cout << "window init fail\n";
			return false;	//window init fail
		}
	}
	else
	{
		std::cout << "SDL init fail\n";
		return false;	//SDL init fail
	}

	//initialise joysticks
	TheInputHandler::Instance()->initialiseJoysticks();

	std::cout << "init success\n";

	//load TextureManager
	if (!TheTextureManager::Instance()->load("assets/animate-alpha.png", "animate", m_pRenderer))
	{
		return false;
	}

	//creating and pushing objects
	m_gameObjects.push_back(new Player(new LoaderParams(100, 100, 128, 82, "animate")));
	m_gameObjects.push_back(new Enemy(new LoaderParams(300, 300, 128, 82, "animate")));

	m_bRunning = true;	//everything inited successfully, start the main loop

	//load MENU state
	m_pGameStateMachine = new GameStateMachine();
	m_pGameStateMachine->changeState(new MenuState());

	return true;
}

bool Game::running()
{
	return m_bRunning;
}

void Game::handleEvents()
{
	//waits and listens for a quit event
	TheInputHandler::Instance()->update();

	if (TheInputHandler::Instance()->isKeyDown(SDL_SCANCODE_RETURN))
	{
		m_pGameStateMachine->changeState(new PlayState());
	}
}

void Game::update()
{
	//use GameStateMachine's update function
	m_pGameStateMachine->update();
}

void Game::render()
{
	SDL_RenderClear(m_pRenderer); //clear the renderer to the draw color

	//use GameStateMachine's render function
	m_pGameStateMachine->render();

	SDL_RenderPresent(m_pRenderer);	//draw to the screen
}

void Game::clean()
{
	std::cout << "cleaning game\n";

	//close the joysticks
	TheInputHandler::Instance()->clean();

	SDL_DestroyWindow(m_pWindow);
	SDL_DestroyRenderer(m_pRenderer);
	SDL_Quit();
}

void Game::quit()
{
	m_bRunning = false;
}<|endoftext|>


<commit_before>#include <iostream>

#include <SFML/Graphics.hpp>
#include "Game.hpp"
#include "Houses.hpp"

const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f);

Game::Game():
  playing(true),
  screen(),
  map(nullptr),
  console(),
  actions(screen, console),
  unitRepository(messages)
{
  sf::ContextSettings settings;
  settings.antialiasingLevel = 8;
  screen.create(sf::VideoMode(800, 600), "Dune 2 - The Maker", sf::Style::Close, settings);
  screen.setFramerateLimit(IDEAL_FPS);
  screen.setMouseCursorVisible(false);

  if (!init()){
    std::cerr << "Failed to initialized game.";
    playing = false;
  }
}

int Game::execute() {

  sf::Clock clock;
  sf::Time timeSinceLastUpdate = sf::Time::Zero;

  while(playing) {
    dt = clock.restart();
    timeSinceLastUpdate += dt;
    while (timeSinceLastUpdate > TimePerFrame)
    {
      timeSinceLastUpdate -= TimePerFrame;

      updateState(TimePerFrame);
    }

    render();

  }

  return 0;
}

bool Game::init() {
  if (!terrain.loadFromFile("graphics/terrain.png")) {
    std::cout << "Failed to read graphics/terrain.png data" << std::endl;
    return false;
  }

  sf::Image temp;
  if (!temp.loadFromFile("graphics/shroud_edges.bmp")) {
    std::cout << "Failed to read graphics/shroud_edges.bmp data" << std::endl;
    return false;
  }

  temp.createMaskFromColor(sf::Color(255, 0, 255));
  shroudEdges.loadFromImage(temp);

  map.reset(new Map(terrain, shroudEdges, messages));
  map->load("maps/4PL_Mountains.ini");

  camera.reset({0,0,800,600});
  screen.setView(camera);

  //init two players
  int idCount = 0;
  players.emplace_back(House::Sardaukar, idCount++);
  players.emplace_back(House::Harkonnen, idCount++);

  units.push_back(std::move(unitRepository.create(Unit::Type::Trike, players[0], sf::Vector2f(256, 256))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Quad, players[1], sf::Vector2f(300, 300))));

  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(400, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(410, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(220, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(430, 500))));

  units.push_back(std::move(unitRepository.create(Unit::Type::Devastator, players[1], sf::Vector2f(500, 200))));

  //register listeners
  typedef thor::ActionContext<std::string> actionContext;

  actions.connect("close", [this](actionContext){playing = false;});

  actions.connect("boxRelease", [this](actionContext){
    for (auto& unit : units){
      if (box.intersects(unit.getBounds())){
        selectUnit(unit);
      }
    }
    box.clear();
  });

  actions.connect("boxStart", [this](actionContext context) {
    if (mouse.getType() != Mouse::Type::Default) {
      return;
    }
    sf::Vector2f toSet = screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera);
    box.setTopLeft(toSet);
  });

  actions.connect("singleSelect", [this](actionContext context){
    sf::Vector2f toCheck = screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera);
    for (auto& unit : units){
      if (unit.getBounds().contains(toCheck))
        selectUnit(unit);
    }
  });

  actions.connect("deselectAll", [this](actionContext){
    actions.disconnect("orderMove");
    mouse.setType(Mouse::Type::Default);
    for (auto& unit : units)
      unit.unselect();
  });

  actions.connect("boxDrag", [this](actionContext){
    box.setBottomRight(screen.mapPixelToCoords(sf::Mouse::getPosition(screen), camera));
  });

  const float cameraSpeed = 700.f;

  actions.connect("cameraLeft", [this, cameraSpeed](actionContext) {camera.move(-dt.asSeconds()*cameraSpeed, 0.f);});
  actions.connect("cameraRight", [this, cameraSpeed](actionContext){camera.move(dt.asSeconds()*cameraSpeed, 0.f); });
  actions.connect("cameraUp", [this, cameraSpeed](actionContext)   {camera.move(0.f, -dt.asSeconds()*cameraSpeed);});
  actions.connect("cameraDown", [this, cameraSpeed](actionContext) {camera.move(0.f, dt.asSeconds()*cameraSpeed); });

  actions.connect("toggleConsole", std::bind(&Console::toggle, &console));

  return true;
}

void Game::render() {
  screen.clear();

  screen.setView(camera);

  screen.draw(*map);

  for (const auto& unit : units)
    screen.draw(unit);

  map->drawShrouded(screen, sf::RenderStates::Default);

  screen.draw(box);

  screen.draw(fpsCounter);

  screen.setView(camera);

  console.display(screen);

  screen.draw(mouse);

  screen.display();
}

void Game::updateState(sf::Time dt) {

  actions.update();
  console.update(dt);

  sf::Vector2i mousePosition = sf::Mouse::getPosition(screen);

  if      (mousePosition.x < 50 ) actions.trigger("cameraLeft");
  else if (mousePosition.y < 50 ) actions.trigger("cameraUp");
  else if (mousePosition.x > 750) actions.trigger("cameraRight");
  else if (mousePosition.y > 550) actions.trigger("cameraDown");

  sf::Vector2f half_of_camera = camera.getSize() / 2.f;
  sf::Vector2f topLeft = camera.getCenter() - (half_of_camera);
  sf::Vector2f downRight = camera.getCenter() + (half_of_camera);

  // Camera constraints take into account an invisible border of 1 cell
  if (topLeft.x <= Cell::TILE_SIZE) camera.setCenter(half_of_camera.x + Cell::TILE_SIZE, camera.getCenter().y);
  if (topLeft.y <= Cell::TILE_SIZE) camera.setCenter(camera.getCenter().x, half_of_camera.y + Cell::TILE_SIZE);

  int max_width = (map->getMaxWidth() -1) * Cell::TILE_SIZE;
  int max_height = (map->getMaxHeight() -1) * Cell::TILE_SIZE;

  if (downRight.x >= max_width) camera.setCenter(max_width - half_of_camera.x, camera.getCenter().y);
  if (downRight.y >= max_height) camera.setCenter(camera.getCenter().x, max_height - half_of_camera.y);

  mouse.setPosition(screen.mapPixelToCoords(mousePosition,camera));

  for (auto& unit: units)
    unit.updateState(units, dt);

  fpsCounter.update(dt);
  map->prepare(screen.mapPixelToCoords(sf::Vector2i(0,0)));
}

void Game::selectUnit(Unit &unit)
{
  unit.select();
  actions.connect("orderMove", [this, &unit](thor::ActionContext<std::string> context){
    unit.orderMove(screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera));
  });
  mouse.setType(Mouse::Type::Move); //at least one unit selected...
}
<commit_msg>camera movement properly uses the time-step instead of the delta<commit_after>#include <iostream>

#include <SFML/Graphics.hpp>
#include "Game.hpp"
#include "Houses.hpp"

const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f);

Game::Game():
  playing(true),
  screen(),
  map(nullptr),
  console(),
  actions(screen, console),
  unitRepository(messages)
{
  sf::ContextSettings settings;
  settings.antialiasingLevel = 8;
  screen.create(sf::VideoMode(800, 600), "Dune 2 - The Maker", sf::Style::Close, settings);
  screen.setFramerateLimit(IDEAL_FPS);
  screen.setMouseCursorVisible(false);

  if (!init()){
    std::cerr << "Failed to initialized game.";
    playing = false;
  }
}

int Game::execute() {

  sf::Clock clock;
  sf::Time timeSinceLastUpdate = sf::Time::Zero;

  while(playing) {
    dt = clock.restart();
    timeSinceLastUpdate += dt;
    while (timeSinceLastUpdate > TimePerFrame)
    {
      timeSinceLastUpdate -= TimePerFrame;

      updateState(TimePerFrame);
    }

    render();

  }

  return 0;
}

bool Game::init() {
  if (!terrain.loadFromFile("graphics/terrain.png")) {
    std::cout << "Failed to read graphics/terrain.png data" << std::endl;
    return false;
  }

  sf::Image temp;
  if (!temp.loadFromFile("graphics/shroud_edges.bmp")) {
    std::cout << "Failed to read graphics/shroud_edges.bmp data" << std::endl;
    return false;
  }

  temp.createMaskFromColor(sf::Color(255, 0, 255));
  shroudEdges.loadFromImage(temp);

  map.reset(new Map(terrain, shroudEdges, messages));
  map->load("maps/4PL_Mountains.ini");

  camera.reset({0,0,800,600});
  screen.setView(camera);

  //init two players
  int idCount = 0;
  players.emplace_back(House::Sardaukar, idCount++);
  players.emplace_back(House::Harkonnen, idCount++);

  units.push_back(std::move(unitRepository.create(Unit::Type::Trike, players[0], sf::Vector2f(256, 256))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Quad, players[1], sf::Vector2f(300, 300))));

  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(400, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(410, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(220, 500))));
  units.push_back(std::move(unitRepository.create(Unit::Type::Soldier, players[0], sf::Vector2f(430, 500))));

  units.push_back(std::move(unitRepository.create(Unit::Type::Devastator, players[1], sf::Vector2f(500, 200))));

  //register listeners
  typedef thor::ActionContext<std::string> actionContext;

  actions.connect("close", [this](actionContext){playing = false;});

  actions.connect("boxRelease", [this](actionContext){
    for (auto& unit : units){
      if (box.intersects(unit.getBounds())){
        selectUnit(unit);
      }
    }
    box.clear();
  });

  actions.connect("boxStart", [this](actionContext context) {
    if (mouse.getType() != Mouse::Type::Default) {
      return;
    }
    sf::Vector2f toSet = screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera);
    box.setTopLeft(toSet);
  });

  actions.connect("singleSelect", [this](actionContext context){
    sf::Vector2f toCheck = screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera);
    for (auto& unit : units){
      if (unit.getBounds().contains(toCheck))
        selectUnit(unit);
    }
  });

  actions.connect("deselectAll", [this](actionContext){
    actions.disconnect("orderMove");
    mouse.setType(Mouse::Type::Default);
    for (auto& unit : units)
      unit.unselect();
  });

  actions.connect("boxDrag", [this](actionContext){
    box.setBottomRight(screen.mapPixelToCoords(sf::Mouse::getPosition(screen), camera));
  });

  const float cameraSpeed = 700.f;

  actions.connect("cameraLeft", [this, cameraSpeed](actionContext) {camera.move(-TimePerFrame.asSeconds()*cameraSpeed, 0.f);});
  actions.connect("cameraRight", [this, cameraSpeed](actionContext){camera.move(TimePerFrame.asSeconds()*cameraSpeed, 0.f); });
  actions.connect("cameraUp", [this, cameraSpeed](actionContext)   {camera.move(0.f, -TimePerFrame.asSeconds()*cameraSpeed);});
  actions.connect("cameraDown", [this, cameraSpeed](actionContext) {camera.move(0.f, TimePerFrame.asSeconds()*cameraSpeed); });

  actions.connect("toggleConsole", std::bind(&Console::toggle, &console));

  return true;
}

void Game::render() {
  screen.clear();

  screen.setView(camera);

  screen.draw(*map);

  for (const auto& unit : units)
    screen.draw(unit);

  map->drawShrouded(screen, sf::RenderStates::Default);

  screen.draw(box);

  screen.draw(fpsCounter);

  screen.setView(camera);

  console.display(screen);

  screen.draw(mouse);

  screen.display();
}

void Game::updateState(sf::Time dt) {

  actions.update();
  console.update(dt);

  sf::Vector2i mousePosition = sf::Mouse::getPosition(screen);

  if      (mousePosition.x < 50 ) actions.trigger("cameraLeft");
  else if (mousePosition.y < 50 ) actions.trigger("cameraUp");
  else if (mousePosition.x > 750) actions.trigger("cameraRight");
  else if (mousePosition.y > 550) actions.trigger("cameraDown");

  sf::Vector2f half_of_camera = camera.getSize() / 2.f;
  sf::Vector2f topLeft = camera.getCenter() - (half_of_camera);
  sf::Vector2f downRight = camera.getCenter() + (half_of_camera);

  // Camera constraints take into account an invisible border of 1 cell
  if (topLeft.x <= Cell::TILE_SIZE) camera.setCenter(half_of_camera.x + Cell::TILE_SIZE, camera.getCenter().y);
  if (topLeft.y <= Cell::TILE_SIZE) camera.setCenter(camera.getCenter().x, half_of_camera.y + Cell::TILE_SIZE);

  int max_width = (map->getMaxWidth() -1) * Cell::TILE_SIZE;
  int max_height = (map->getMaxHeight() -1) * Cell::TILE_SIZE;

  if (downRight.x >= max_width) camera.setCenter(max_width - half_of_camera.x, camera.getCenter().y);
  if (downRight.y >= max_height) camera.setCenter(camera.getCenter().x, max_height - half_of_camera.y);

  mouse.setPosition(screen.mapPixelToCoords(mousePosition,camera));

  for (auto& unit: units)
    unit.updateState(units, dt);

  fpsCounter.update(dt);
  map->prepare(screen.mapPixelToCoords(sf::Vector2i(0,0)));
}

void Game::selectUnit(Unit &unit)
{
  unit.select();
  actions.connect("orderMove", [this, &unit](thor::ActionContext<std::string> context){
    unit.orderMove(screen.mapPixelToCoords(mouse.getHotspot(*context.event), camera));
  });
  mouse.setType(Mouse::Type::Move); //at least one unit selected...
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <chrono>
#include "../htmlfile2.h"
#include "../../DesktopEditor/common/File.h"
#include "../../DesktopEditor/common/Directory.h"
#include "../../OfficeUtils/src/OfficeUtils.h"

void getDirectories(std::wstring sDirectory, std::vector<std::wstring>& arrDirectory)
{
    arrDirectory.push_back(sDirectory);
    for(std::wstring sT : NSDirectory::GetDirectories(sDirectory))
        getDirectories(sT, arrDirectory);
}

int main()
{
    bool bBatchMode = false;
    bool bMhtMode = true;
    if(bBatchMode)
    {
        // Директория файлов
        std::wstring sDirectory = NSFile::GetProcessDirectory() + L"/../../../examples/html";
        // Вложенные директории
        std::vector<std::wstring> arrDirectory;
        getDirectories(sDirectory, arrDirectory);
        COfficeUtils oZip;
        // Выставляем временную директорию
        std::wstring sTmp = NSFile::GetProcessDirectory() + L"/tmp";
        NSDirectory::DeleteDirectory(sTmp);
        NSDirectory::CreateDirectory(sTmp);

        for(std::wstring sD : arrDirectory)
        {
            std::vector<std::wstring> arrFiles = NSDirectory::GetFiles(sD);
            // Директория, где будем создавать docx
            size_t nPos = sD.find(L"/html");
            std::wstring sOutputDirectory = sD.insert(nPos + 5, L"-res");
            NSDirectory::CreateDirectory(sOutputDirectory);

            for(std::wstring sFile : arrFiles)
            {
                std::wstring sFileName = NSFile::GetFileName(sFile);
                std::wcout << sFileName << std::endl;
                HRESULT nResConvert;
                CHtmlFile2 oFile;
                oFile.SetTmpDirectory(sTmp);
                std::chrono::system_clock::time_point begin = std::chrono::system_clock::now();
                std::chrono::system_clock::time_point end;
                if(bMhtMode)
                {
                    if(!oFile.IsMhtFile(sFile))
                    {
                        std::cout << "This isn't a mht file" << std::endl;
                        continue;
                    }
                    end = std::chrono::system_clock::now();
                    nResConvert = oFile.OpenMht(sFile, sTmp);
                }
                else
                {
                    if(!oFile.IsHtmlFile(sFile))
                    {
                        std::cout << "This isn't a html file" << std::endl;
                        continue;
                    }
                    end = std::chrono::system_clock::now();
                    nResConvert = oFile.OpenHtml(sFile, sTmp);
                }
                std::chrono::duration<long, std::milli> dur1 = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
                begin = std::chrono::system_clock::now();
                std::chrono::duration<long, std::milli> dur2 = std::chrono::duration_cast<std::chrono::milliseconds>(begin - end);
                if(nResConvert == S_OK)
                {
                    std::cout << "Success " << dur1.count() << " " << dur2.count() << std::endl;
                    oZip.CompressFileOrDirectory(sTmp, sOutputDirectory + L"/" + sFileName + L".docx");
                    NSDirectory::DeleteDirectory(sTmp + L"/word/media");
                }
                else
                    std::cout << "Failure" << std::endl;
            }
        }
    }
    else
    {
        HRESULT nResConvert = S_FALSE;
        // Директория, где будем создавать docx
        std::wstring sOutputDirectory = NSFile::GetProcessDirectory() + L"/res";
        NSDirectory::DeleteDirectory(sOutputDirectory);
        NSDirectory::CreateDirectory(sOutputDirectory);

        CHtmlParams oParams;
        oParams.SetAuthors(L"last first middle;last2 first2 middle2");
        oParams.SetGenres(L"fantazy, drama");
        oParams.SetTitle(L"The Last Wish");
        oParams.SetDate(L"2010-06-03T04:00:00+00:00");
        oParams.SetDescription(L"Description");

        // Файл, который открываем
        std::wstring sFile = NSFile::GetProcessDirectory() + L"/../../../examples/test.mht";
        CHtmlFile2 oFile;
        oFile.SetTmpDirectory(sOutputDirectory);
        nResConvert = (bMhtMode ? oFile.OpenMht(sFile, sOutputDirectory, &oParams) : oFile.OpenHtml(sFile, sOutputDirectory, &oParams));

        if(nResConvert == S_OK)
        {
            std::cout << "Success" << std::endl;
            COfficeUtils oZip;
            oZip.CompressFileOrDirectory(sOutputDirectory, sOutputDirectory + L"/Aggregate.docx");
        }
        else
            std::cout << "Failure" << std::endl;
    }
    std::cout << "THE END" << std::endl;
    return 0;
}
<commit_msg>update test htmlfile2<commit_after>#include <iostream>
#include <vector>
#include <chrono>
#include "../htmlfile2.h"
#include "../../DesktopEditor/common/File.h"
#include "../../DesktopEditor/common/Directory.h"
#include "../../OfficeUtils/src/OfficeUtils.h"

void getDirectories(const std::wstring& sDirectory, std::vector<std::wstring>& arrDirectory)
{
    arrDirectory.push_back(sDirectory);
    for(const std::wstring& sT : NSDirectory::GetDirectories(sDirectory))
        getDirectories(sT, arrDirectory);
}

int main()
{
    bool bBatchMode = false;
    bool bMhtMode = true;
    if(bBatchMode)
    {
        // Директория файлов
        std::wstring sDirectory = NSFile::GetProcessDirectory() + L"/../../../examples/html";
        // Вложенные директории
        std::vector<std::wstring> arrDirectory;
        getDirectories(sDirectory, arrDirectory);
        COfficeUtils oZip;
        // Выставляем временную директорию
        std::wstring sTmp = NSFile::GetProcessDirectory() + L"/tmp";
        NSDirectory::DeleteDirectory(sTmp);
        NSDirectory::CreateDirectory(sTmp);

        for(std::wstring sD : arrDirectory)
        {
            std::vector<std::wstring> arrFiles = NSDirectory::GetFiles(sD);
            // Директория, где будем создавать docx
            size_t nPos = sD.find(L"/html");
            std::wstring sOutputDirectory = sD.insert(nPos + 5, L"-res");
            NSDirectory::CreateDirectory(sOutputDirectory);

            for(const std::wstring& sFile : arrFiles)
            {
                std::wstring sFileName = NSFile::GetFileName(sFile);
                std::wcout << sFileName << std::endl;
                HRESULT nResConvert;
                CHtmlFile2 oFile;
                oFile.SetTmpDirectory(sTmp);
                std::chrono::system_clock::time_point begin = std::chrono::system_clock::now();
                std::chrono::system_clock::time_point end;
                if(bMhtMode)
                {
                    if(!oFile.IsMhtFile(sFile))
                    {
                        std::cout << "This isn't a mht file" << std::endl;
                        continue;
                    }
                    end = std::chrono::system_clock::now();
                    nResConvert = oFile.OpenMht(sFile, sTmp);
                }
                else
                {
                    if(!oFile.IsHtmlFile(sFile))
                    {
                        std::cout << "This isn't a html file" << std::endl;
                        continue;
                    }
                    end = std::chrono::system_clock::now();
                    nResConvert = oFile.OpenHtml(sFile, sTmp);
                }
                std::chrono::duration<long, std::milli> dur1 = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
                begin = std::chrono::system_clock::now();
                std::chrono::duration<long, std::milli> dur2 = std::chrono::duration_cast<std::chrono::milliseconds>(begin - end);
                if(nResConvert == S_OK)
                {
                    std::cout << "Success " << dur1.count() << " " << dur2.count() << std::endl;
                    oZip.CompressFileOrDirectory(sTmp, sOutputDirectory + L"/" + sFileName + L".docx");
                    NSDirectory::DeleteDirectory(sTmp + L"/word/media");
                }
                else
                    std::cout << "Failure" << std::endl;
            }
        }
    }
    else
    {
        HRESULT nResConvert = S_FALSE;
        // Директория, где будем создавать docx
        std::wstring sOutputDirectory = NSFile::GetProcessDirectory() + L"/res";
        NSDirectory::DeleteDirectory(sOutputDirectory);
        NSDirectory::CreateDirectory(sOutputDirectory);

        CHtmlParams oParams;
        oParams.SetAuthors(L"last first middle;last2 first2 middle2");
        oParams.SetGenres(L"fantazy, drama");
        oParams.SetTitle(L"The Last Wish");
        oParams.SetDate(L"2010-06-03T04:00:00+00:00");
        oParams.SetDescription(L"Description");

        // Файл, который открываем
        std::wstring sFile = NSFile::GetProcessDirectory() + L"/../../../examples/test.mht";
        CHtmlFile2 oFile;
        oFile.SetTmpDirectory(sOutputDirectory);
        nResConvert = (bMhtMode ? oFile.OpenMht(sFile, sOutputDirectory, &oParams) : oFile.OpenHtml(sFile, sOutputDirectory, &oParams));

        if(nResConvert == S_OK)
        {
            std::cout << "Success" << std::endl;
            COfficeUtils oZip;
            oZip.CompressFileOrDirectory(sOutputDirectory, sOutputDirectory + L"/Aggregate.docx");
        }
        else
            std::cout << "Failure" << std::endl;
    }
    std::cout << "THE END" << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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
 **/

#include <string>
#include <vector>

#include "modules/planning/scenarios/traffic_light/unprotected_right_turn/stage_intersection_cruise.h"

#include "modules/perception/proto/perception_obstacle.pb.h"

#include "cyber/common/log.h"
#include "modules/common/time/time.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_context.h"
#include "modules/planning/tasks/deciders/decider_creep.h"

namespace apollo {
namespace planning {
namespace scenario {
namespace traffic_light {

using common::TrajectoryPoint;
using hdmap::PathOverlap;

Stage::StageStatus
TrafficLightUnprotectedRightTurnStageIntersectionCruise::Process(

    const TrajectoryPoint& planning_init_point, Frame* frame) {
  ADEBUG << "stage: IntersectionCruise";
  CHECK_NOTNULL(frame);

  bool plan_ok = ExecuteTaskOnReferenceLine(planning_init_point, frame);
  if (!plan_ok) {
    AERROR << "TrafficLightUnprotectedRightTurnStageIntersectionCruise "
           << "plan error";
  }

  /* TODO(all): to be fixed
  const auto& reference_line_info = frame->reference_line_info().front();

  // check if the traffic_light is still along reference_line
  std::string traffic_light_overlap_id =
      PlanningContext::GetScenarioInfo()->next_traffic_light_overlap.object_id;
  if (CheckTrafficLightDone(reference_line_info, traffic_light_overlap_id)) {
    return FinishScenario();
  }

  // check pass intersection
  // TODO(all): update when pnc-junction is ready
  constexpr double kIntersectionLength = 10.0;  // unit: m
  const double adc_back_edge_s = reference_line_info.AdcSlBoundary().start_s();
  const double distance_adc_pass_traffic_light =
      adc_back_edge_s -
      PlanningContext::GetScenarioInfo()->next_traffic_light_overlap.end_s;
  if (distance_adc_pass_traffic_light > kIntersectionLength) {
    return FinishStage();
  }
  */

  return Stage::RUNNING;
}

Stage::StageStatus
TrafficLightUnprotectedRightTurnStageIntersectionCruise::FinishStage() {
  return FinishScenario();
}

}  // namespace traffic_light
}  // namespace scenario
}  // namespace planning
}  // namespace apollo
<commit_msg>planning: intersection_cruise stage for traffic_light_unprotected_right_turn scenario<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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
 **/
#include "modules/planning/scenarios/traffic_light/unprotected_right_turn/stage_intersection_cruise.h"

#include "cyber/common/log.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_context.h"
#include "modules/planning/scenarios/util/util.h"

namespace apollo {
namespace planning {
namespace scenario {
namespace traffic_light {

using common::TrajectoryPoint;

Stage::StageStatus
TrafficLightUnprotectedRightTurnStageIntersectionCruise::Process(
    const TrajectoryPoint& planning_init_point, Frame* frame) {
  ADEBUG << "stage: IntersectionCruise";
  CHECK_NOTNULL(frame);

  bool plan_ok = ExecuteTaskOnReferenceLine(planning_init_point, frame);
  if (!plan_ok) {
    AERROR << "TrafficLightUnprotectedRightTurnStageIntersectionCruise "
        << "plan error";
  }

  const auto& reference_line_info = frame->reference_line_info().front();

  // check pass pnc_junction
  // TODO(all): remove when pnc_junction completely available on map
  const auto& pnc_junction_overlaps =
      reference_line_info.reference_line().map_path().pnc_junction_overlaps();
  if (pnc_junction_overlaps.size() == 0) {
    // pnc_junction not exist on map, use current traffic_light's end_s
    if (PlanningContext::GetScenarioInfo()
        ->current_traffic_light_overlaps.size() == 0) {
      return FinishStage();
    }

    constexpr double kIntersectionPassDist = 20.0;  // unit: m
    const double adc_back_edge_s =
        reference_line_info.AdcSlBoundary().start_s();
    const double traffic_light_end_s = PlanningContext::GetScenarioInfo()
        ->current_traffic_light_overlaps[0].end_s;
    const double distance_adc_pass_traffic_light = adc_back_edge_s -
        traffic_light_end_s;
    ADEBUG << "distance_adc_pass_traffic_light["
        << distance_adc_pass_traffic_light
        << "] traffic_light_end_s[" << traffic_light_end_s << "]";

    if (distance_adc_pass_traffic_light >= kIntersectionPassDist) {
      return FinishStage();
    } else {
      return Stage::RUNNING;
    }
  }

  if (!scenario::CheckInsidePnCJunction(reference_line_info)) {
    return FinishStage();
  }

  return Stage::RUNNING;
}

Stage::StageStatus
TrafficLightUnprotectedRightTurnStageIntersectionCruise::FinishStage() {
  return FinishScenario();
}

}  // namespace traffic_light
}  // namespace scenario
}  // namespace planning
}  // namespace apollo
<|endoftext|>


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

#include "MacroDefinitions.h"
#include "../ClangHelpers.h"

#include "OOModel/src/expressions/ReferenceExpression.h"
#include "OOModel/src/declarations/Project.h"

namespace CppImport {

MacroDefinitions::MacroDefinitions(ClangHelpers& clang) : clang_{clang}
{
	if (directoryToNamespaceMap_.isEmpty())
	{
		directoryToNamespaceMap_.insert("ModelBase", "Model");
		directoryToNamespaceMap_.insert("VisualizationBase", "Visualization");
		directoryToNamespaceMap_.insert("InteractionBase", "Interaction");
	}
}

QString MacroDefinitions::definitionName(const clang::MacroDirective* md) const
{
	auto it = definitions_.find(md);

	return it != definitions_.end() ? *it : nullptr;
}

QString MacroDefinitions::signature(const clang::MacroDirective* md) const
{
	QString namespaceName, fileName;

	auto parentProject = clang_.projectForLocation(md->getLocation());
	if (parentProject != clang_.rootProject())
		return parentProject->name() + "/" + definitionName(md);
	else
		return "/ExternalMacro/" + definitionName(md);
}

OOModel::ReferenceExpression* MacroDefinitions::expansionQualifier(const clang::MacroDirective* md) const
{
	auto parentProject = clang_.projectForLocation(md->getLocation());
	if (parentProject == clang_.rootProject())
		return new OOModel::ReferenceExpression{"ExternalMacro"};

	return {};
}

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

#include "MacroDefinitions.h"
#include "../ClangHelpers.h"

#include "OOModel/src/expressions/ReferenceExpression.h"
#include "OOModel/src/declarations/Project.h"

namespace CppImport {

MacroDefinitions::MacroDefinitions(ClangHelpers& clang) : clang_{clang}
{
	if (directoryToNamespaceMap_.isEmpty())
	{
		directoryToNamespaceMap_.insert("ModelBase", "Model");
		directoryToNamespaceMap_.insert("VisualizationBase", "Visualization");
		directoryToNamespaceMap_.insert("InteractionBase", "Interaction");
	}
}

QString MacroDefinitions::definitionName(const clang::MacroDirective* md) const
{
	auto it = definitions_.find(md);

	return it != definitions_.end() ? *it : nullptr;
}

QString MacroDefinitions::signature(const clang::MacroDirective* md) const
{
	auto parentProject = clang_.projectForLocation(md->getLocation());
	if (parentProject != clang_.rootProject())
		return parentProject->name() + "/" + definitionName(md);
	else
		return "/ExternalMacro/" + definitionName(md);
}

OOModel::ReferenceExpression* MacroDefinitions::expansionQualifier(const clang::MacroDirective* md) const
{
	auto parentProject = clang_.projectForLocation(md->getLocation());
	if (parentProject == clang_.rootProject())
		return new OOModel::ReferenceExpression{"ExternalMacro"};

	return {};
}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2013-2014 gtalent2@gmail.com
 *
 * 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.
 */
#ifdef WITH_SDL
#include <vector>

#include <SDL.h>

#include "_sdlglobs.hpp"
#include "core.hpp"

namespace wombat {
namespace core {

class EventQueueSemaphore: public BaseSemaphore {
	private:
		std::queue<Event> m_posts;
		Mutex m_mutex;

	public:
		/**
		 * Constructor
		 */
		EventQueueSemaphore();

		/**
		 * Destructor
		 */
		~EventQueueSemaphore();

		Event wait();

		Event wait(uint64 timeout);

		void post(Event wakeup = SemaphorePost);

		int popPost(Event &post);

		bool hasPosts();

	// disallow copying
	private:
		EventQueueSemaphore(const EventQueueSemaphore&);
		EventQueueSemaphore &operator=(const EventQueueSemaphore&);
} _mainSemaphore;

TaskProcessor _taskProcessor(&_mainSemaphore);

const auto Event_DrawEvent = SDL_RegisterEvents(1);
const auto Event_SemaporePost = SDL_RegisterEvents(1);
const auto Event_SemaporeTimeout = SDL_RegisterEvents(1);

std::vector<Drawer*> drawers;
std::vector<Graphics*> graphicsInstances;
SDL_Window *display = 0;
SDL_Renderer *renderer = 0;

extern std::vector<EventHandler> eventHandlers;
extern bool _running;

Key toWombatKey(SDL_Event);
void _updateEventTime();

// EventQueueSemaphore Implementation

EventQueueSemaphore::EventQueueSemaphore() {
}

EventQueueSemaphore::~EventQueueSemaphore() {
}

Event EventQueueSemaphore::wait() {
	return UnknownEvent;
}

Event EventQueueSemaphore::wait(uint64 timeout) {
	return UnknownEvent;
}

void EventQueueSemaphore::post(Event post) {
	m_mutex.lock();
	m_posts.push(post);
	SDL_Event ev;
	SDL_zero(ev);
	ev.type = Event_SemaporePost;
	SDL_PushEvent(&ev);
	m_mutex.unlock();
}

int EventQueueSemaphore::popPost(Event &post) {
	m_mutex.lock();
	if (hasPosts()) {
		post = m_posts.front();
		m_posts.pop();
		m_mutex.unlock();
		return 0;
	}
	m_mutex.unlock();
	return 1;
}

bool EventQueueSemaphore::hasPosts() {
	return m_posts.size();
}

// Main TaskProcessor modifiers

void addTask(std::function<TaskState(Event)> task, TaskState state) {
	_taskProcessor.addTask(task, state);
}

void addTask(Task *task, TaskState state) {
	_taskProcessor.addTask(task, state);
}

void draw() {
	SDL_Event ev;
	SDL_zero(ev);
	ev.type = Event_DrawEvent;
	SDL_PushEvent(&ev);
}

void _draw() {
	SDL_RenderClear(renderer);
	for (int i = 0; i < drawers.size(); i++) {
		drawers[i]->draw(graphicsInstances[i]);
	}
	SDL_RenderPresent(renderer);
}

void main() {
	// handle events
	SDL_Event sev;
	TaskState taskState = TaskState::Waiting;
	while (_running) {
		if (taskState.state == TaskState::Running) {
			if (SDL_WaitEventTimeout(&sev, taskState.sleepDuration) == 0) {
				// yes... SDL_WaitEventTimeout uses 0 indicate failure...
				sev.type = Event_SemaporeTimeout;
			}
		} else {
			SDL_WaitEvent(&sev);
		}

		const auto t = sev.type;
		Event ev;
		_updateEventTime();
		if (t == Event_DrawEvent) {
			_draw();
		} else if (sev.type == Event_SemaporeTimeout) {
			ev.m_type = Timeout;
			taskState = _taskProcessor.run(ev);
		} else if (sev.type == Event_SemaporePost) {
			if (_mainSemaphore.popPost(ev) == 0) {
				taskState = _taskProcessor.run(ev);
			}
		} else {
			if (t == SDL_QUIT) {
				ev.m_type = QuitEvent;
			} else if (t == SDL_KEYUP) {
				ev.m_type = KeyUpEvent;
				ev.m_body.key = toWombatKey(sev);
			} else if (t == SDL_KEYDOWN) {
				ev.m_type = KeyDownEvent;
				ev.m_body.key = toWombatKey(sev);
			}

			for (auto f : eventHandlers) {
				f(ev);
			}
		}
	}
}

int init(bool fullscreen, int w, int h) {
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) == -1) {
		return -1;
	}

	auto flags = SDL_WINDOW_OPENGL;
	if (fullscreen) {
		flags = (SDL_WindowFlags) (flags | SDL_WINDOW_FULLSCREEN_DESKTOP);
	} else {
		flags = (SDL_WindowFlags) (flags | SDL_WINDOW_RESIZABLE);
	}
	display = SDL_CreateWindow("Wombat", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags);
	if (!display)
		return -3;
	renderer = SDL_CreateRenderer(display, -1, SDL_RENDERER_ACCELERATED);

	_running = true; _updateEventTime();
	return 0;
}

void addDrawer(Drawer *d) {
	graphicsInstances.push_back(new Graphics());
	drawers.push_back(d);
}

}
}

#endif
<commit_msg>Fixed event processing not to feed garbage events to event handlers.<commit_after>/*
 * Copyright 2013-2014 gtalent2@gmail.com
 *
 * 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.
 */
#ifdef WITH_SDL
#include <vector>

#include <SDL.h>

#include "_sdlglobs.hpp"
#include "core.hpp"

namespace wombat {
namespace core {

class EventQueueSemaphore: public BaseSemaphore {
	private:
		std::queue<Event> m_posts;
		Mutex m_mutex;

	public:
		/**
		 * Constructor
		 */
		EventQueueSemaphore();

		/**
		 * Destructor
		 */
		~EventQueueSemaphore();

		Event wait();

		Event wait(uint64 timeout);

		void post(Event wakeup = SemaphorePost);

		int popPost(Event &post);

		bool hasPosts();

	// disallow copying
	private:
		EventQueueSemaphore(const EventQueueSemaphore&);
		EventQueueSemaphore &operator=(const EventQueueSemaphore&);
} _mainSemaphore;

TaskProcessor _taskProcessor(&_mainSemaphore);

const auto Event_DrawEvent = SDL_RegisterEvents(1);
const auto Event_SemaporePost = SDL_RegisterEvents(1);
const auto Event_SemaporeTimeout = SDL_RegisterEvents(1);

std::vector<Drawer*> drawers;
std::vector<Graphics*> graphicsInstances;
SDL_Window *display = 0;
SDL_Renderer *renderer = 0;

extern std::vector<EventHandler> eventHandlers;
extern bool _running;

Key toWombatKey(SDL_Event);
void _updateEventTime();

// EventQueueSemaphore Implementation

EventQueueSemaphore::EventQueueSemaphore() {
}

EventQueueSemaphore::~EventQueueSemaphore() {
}

Event EventQueueSemaphore::wait() {
	return UnknownEvent;
}

Event EventQueueSemaphore::wait(uint64 timeout) {
	return UnknownEvent;
}

void EventQueueSemaphore::post(Event post) {
	m_mutex.lock();
	m_posts.push(post);
	SDL_Event ev;
	SDL_zero(ev);
	ev.type = Event_SemaporePost;
	SDL_PushEvent(&ev);
	m_mutex.unlock();
}

int EventQueueSemaphore::popPost(Event &post) {
	m_mutex.lock();
	if (hasPosts()) {
		post = m_posts.front();
		m_posts.pop();
		m_mutex.unlock();
		return 0;
	}
	m_mutex.unlock();
	return 1;
}

bool EventQueueSemaphore::hasPosts() {
	return m_posts.size();
}

// Main TaskProcessor modifiers

void addTask(std::function<TaskState(Event)> task, TaskState state) {
	_taskProcessor.addTask(task, state);
}

void addTask(Task *task, TaskState state) {
	_taskProcessor.addTask(task, state);
}

void draw() {
	SDL_Event ev;
	SDL_zero(ev);
	ev.type = Event_DrawEvent;
	SDL_PushEvent(&ev);
}

void _draw() {
	SDL_RenderClear(renderer);
	for (int i = 0; i < drawers.size(); i++) {
		drawers[i]->draw(graphicsInstances[i]);
	}
	SDL_RenderPresent(renderer);
}

void main() {
	// handle events
	SDL_Event sev;
	TaskState taskState = TaskState::Waiting;
	while (_running) {
		if (taskState.state == TaskState::Running) {
			if (SDL_WaitEventTimeout(&sev, taskState.sleepDuration) == 0) {
				// yes... SDL_WaitEventTimeout uses 0 indicate failure...
				sev.type = Event_SemaporeTimeout;
			}
		} else {
			SDL_WaitEvent(&sev);
		}

		const auto t = sev.type;
		Event ev;
		_updateEventTime();
		if (t == Event_DrawEvent) {
			_draw();
		} else if (sev.type == Event_SemaporeTimeout) {
			ev.m_type = Timeout;
			taskState = _taskProcessor.run(ev);
		} else if (sev.type == Event_SemaporePost) {
			if (_mainSemaphore.popPost(ev) == 0) {
				taskState = _taskProcessor.run(ev);
			}
		} else if (t == SDL_QUIT) {
			ev.m_type = QuitEvent;

			for (auto f : eventHandlers) {
				f(ev);
			}
		} else if (t == SDL_KEYUP) {
			ev.m_type = KeyUpEvent;
			ev.m_body.key = toWombatKey(sev);

			for (auto f : eventHandlers) {
				f(ev);
			}
		} else if (t == SDL_KEYDOWN) {
			ev.m_type = KeyDownEvent;
			ev.m_body.key = toWombatKey(sev);

			for (auto f : eventHandlers) {
				f(ev);
			}
		}
	}
}

int init(bool fullscreen, int w, int h) {
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) == -1) {
		return -1;
	}

	auto flags = SDL_WINDOW_OPENGL;
	if (fullscreen) {
		flags = (SDL_WindowFlags) (flags | SDL_WINDOW_FULLSCREEN_DESKTOP);
	} else {
		flags = (SDL_WindowFlags) (flags | SDL_WINDOW_RESIZABLE);
	}
	display = SDL_CreateWindow("Wombat", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags);
	if (!display)
		return -3;
	renderer = SDL_CreateRenderer(display, -1, SDL_RENDERER_ACCELERATED);

	_running = true; _updateEventTime();
	return 0;
}

void addDrawer(Drawer *d) {
	graphicsInstances.push_back(new Graphics());
	drawers.push_back(d);
}

}
}

#endif
<|endoftext|>


<commit_before>#include <pybind11/embed.h>

#include <iostream>
#include <unistd.h>
#include <vector>

#ifdef __APPLE__
#include <util.h>
#include <sys/ioctl.h>
#else
#include <pty.h>
#endif

#include <termios.h>
#include <fcntl.h>
#include <signal.h>

#include <string.h>

#include <sys/select.h>
#include <sys/wait.h>

#include "plugin_manager.h"
#include "plugin.h"
#include "term_network.h"
#include "term_data_handler.h"
#include "term_context.h"
#include "term_window.h"

#include "PortableThread.h"

#include "app_config_impl.h"

static
void delete_data(void * data);

class TermNetworkPty
        : public virtual Plugin
        , public virtual TermNetwork
        , public virtual PortableThread::IPortableRunnable
{
public:
    TermNetworkPty() :
        Plugin()
        , m_Name("term_network_use_pty")
        , m_Description("terminal network plugin using pty")
        , m_Version(1)
        , m_Rows(0)
        , m_Cols(0)
        , m_MasterFD(-1)
        , m_ReadBuffer(8192)
        , m_PtyReaderThread(this)
    {
    }

    virtual ~TermNetworkPty() = default;

    MultipleInstancePluginPtr NewInstance() override {
        return MultipleInstancePluginPtr{new TermNetworkPty, delete_data};
    }

    bool m_Stopped;
    void Disconnect() override {
        m_Stopped = true;

        if (m_MasterFD == -1)
            return;

        close(m_MasterFD);
        m_PtyReaderThread.Join();
    }

    const char * GetName() override {
        return m_Name.c_str();
    }
    const char * GetDescription() override {
        return m_Description.c_str();
    }

    uint32_t GetVersion() override {
        return m_Version;
    }

    ContextPtr GetPluginContext() const override {
        return m_Context;
    }

    AppConfigPtr GetPluginConfig() const override {
        return m_PluginConfig;
    }

    void InitPlugin(ContextPtr context,
                    AppConfigPtr plugin_config) override {
        m_Context = context;
        m_PluginConfig = plugin_config;
    }
private:
    std::string m_Name;
    std::string m_Description;
    uint32_t m_Version;

protected:
    ContextPtr m_Context;
    AppConfigPtr m_PluginConfig;

    std::shared_ptr<char> m_TermName;
    std::shared_ptr<char> m_CmdLine;
    std::vector<char *> m_Args;

public:
    void BuildEnviron() {
        m_Envs.clear();

        extern char ** environ;

        char ** tmp = environ;

        std::string term_name = "TERM=" + GetPluginContext()->GetAppConfig()->GetEntry("/term/term_name", "xterm-256color");

        m_TermName = {strdup(term_name.c_str()), [](char * data) {
                free(data);
            }};

        bool term_updated = false;
        while(*tmp) {
            if (term_name != "NOT FOUND" && !strncmp(*tmp, "TERM=", strlen("TERM=")))
            {
                m_Envs.push_back(m_TermName.get());
                term_updated = true;
            }
            else
            {
                m_Envs.push_back(*tmp);
            }
            tmp++;
        }

        if (!term_updated) {
            m_Envs.push_back(m_TermName.get());
        }

        m_Envs.push_back(NULL);
    }

    void BuildCmdLine(const std::string & cmd_line)
    {
        m_CmdLine = {
            strdup(cmd_line.c_str()), [](char * data) {
                free(data);
            }};

        char * token = strtok(m_CmdLine.get(), " ");

        m_Args.clear();

        while(token != NULL) {
            m_Args.push_back(token);
            token = strtok(NULL, " ");
        }

        m_Args.push_back(NULL);
    }

    void Connect(const char * host, int port, const char * user_name, const char * password) override {
        (void)host;
        (void)port;
        (void)user_name;
        (void)password;

        m_Stopped = false;

        pid_t pid;
        struct winsize ws {
            (unsigned short)m_Rows,
                    (unsigned short)m_Cols,
                    0,
                    0
                    };

        std::string shell = GetPluginConfig()->GetEntry("shell", "NOT FOUND");

        if (shell == "NOT FOUND")
        {
            char * sys_shell = getenv("SHELL");

            if (sys_shell)
                shell = std::string(sys_shell);
            else
                shell = std::string("/bin/bash -i -l");
        }

        BuildEnviron();

        BuildCmdLine(shell);

        pid = forkpty(&m_MasterFD, NULL, NULL, &ws);

        // impossible to fork
        if (pid < 0) {
            std::cerr << "pty fork failed" << std::endl;
            return;
        }
        // child
        else if (pid == 0) {
#ifdef __APPLE__
            execve(m_Args[0], &m_Args[0], &m_Envs[0]);
#else
            execvpe(m_Args[0], &m_Args[0], &m_Envs[0]);
#endif
        }
        // parent
        else {
            m_PtyPid = pid;
            int flags = fcntl(m_MasterFD, F_GETFL, 0);
            fcntl(m_MasterFD, F_SETFL, flags | O_NONBLOCK);

            m_PtyReaderThread.Start();
        }
    }

    void Send(const std::vector<unsigned char> & data, size_t n) override {
        if (write(m_MasterFD, &data[0], n) <= 0) {
            std::cerr << "write failed:" << strerror(errno) << std::endl;
        }
    }

    void Resize(uint32_t row, uint32_t col) override {
        m_Rows = row;
        m_Cols = col;
        /*
          struct winsize {
          unsigned short ws_row;
          unsigned short ws_col;
          unsigned short ws_xpixel;   / unused /
          unsigned short ws_ypixel;   / unused /
          };
        */

        if (m_MasterFD == -1)
            return;

        struct winsize ws {
            (unsigned short)row,
                    (unsigned short)col,
                    0,
                    0
                    };

        int result = ioctl(m_MasterFD, TIOCSWINSZ, &ws);
        if (result) {
            std::cerr << "resize result:" << result << "," << errno
                      << ", " << EINVAL
                      << ", " << ENOTTY
                      << ", " << EPERM
                      << ", " << strerror(errno)
                      << std::endl;
        }
    }

    unsigned long Run(void * /*pArgument*/) override {
        struct timeval tv;

        TermContextPtr context = std::dynamic_pointer_cast<TermContext>(GetPluginContext());

        if (!context)
            return 0;

        TermDataHandlerPtr term_data_handler =
                context->GetTermDataHandler();
        TermWindowPtr term_window =
                context->GetTermWindow();

        for (;;) {

            fd_set          read_fd;
            fd_set          except_fd;

            tv.tv_sec = 1;
            tv.tv_usec = 0;

            FD_ZERO(&read_fd);
            FD_ZERO(&except_fd);

            FD_SET(m_MasterFD, &read_fd);
            FD_SET(m_MasterFD, &except_fd);

            int result = select(m_MasterFD+1, &read_fd, NULL, &except_fd, &tv);

            if (m_Stopped)
                break;

            if (result == -1) {
                if (errno == EINTR) {
                    continue;
                }

                std::cerr << "select failed with err:" << errno << std::endl;
                break;
            } else if (result == 0) {
                //timeout
                continue;
            }

            if (FD_ISSET(m_MasterFD, &except_fd))
            {
                term_window->Close();
                break;
            }

            if (FD_ISSET(m_MasterFD, &read_fd))
            {
                int count = read(m_MasterFD, &m_ReadBuffer[0], m_ReadBuffer.size());
                if (count == -1) {
                    if (errno == EINTR)
                        continue;

                    std::cerr << "read failed\n" << std::endl;
                    term_window->Close();
                    break;
                }

                if (count > 0) {
                    term_data_handler->OnData(m_ReadBuffer, count);
                }
            }
        }
        return 0;
    }
private:
    uint32_t m_Rows;
    uint32_t m_Cols;
    int m_MasterFD;
    std::vector<unsigned char> m_ReadBuffer;
    PortableThread::CPortableThread m_PtyReaderThread;
    std::vector<char *> m_Envs;
    pid_t m_PtyPid;
};

void delete_data(void * data) {
    delete (Plugin*)data;
}

extern "C"
void register_plugins(PluginManagerPtr plugin_manager) {
    plugin_manager->RegisterPlugin(PluginPtr {new TermNetworkPty, delete_data});;
}
<commit_msg>add tcdrain for write pty<commit_after>#include <pybind11/embed.h>

#include <iostream>
#include <unistd.h>
#include <vector>

#ifdef __APPLE__
#include <util.h>
#include <sys/ioctl.h>
#else
#include <pty.h>
#endif

#include <termios.h>
#include <fcntl.h>
#include <signal.h>

#include <string.h>

#include <sys/select.h>
#include <sys/wait.h>

#include "plugin_manager.h"
#include "plugin.h"
#include "term_network.h"
#include "term_data_handler.h"
#include "term_context.h"
#include "term_window.h"

#include "PortableThread.h"

#include "app_config_impl.h"

static
void delete_data(void * data);

class TermNetworkPty
        : public virtual Plugin
        , public virtual TermNetwork
        , public virtual PortableThread::IPortableRunnable
{
public:
    TermNetworkPty() :
        Plugin()
        , m_Name("term_network_use_pty")
        , m_Description("terminal network plugin using pty")
        , m_Version(1)
        , m_Rows(0)
        , m_Cols(0)
        , m_MasterFD(-1)
        , m_ReadBuffer(8192)
        , m_PtyReaderThread(this)
    {
    }

    virtual ~TermNetworkPty() = default;

    MultipleInstancePluginPtr NewInstance() override {
        return MultipleInstancePluginPtr{new TermNetworkPty, delete_data};
    }

    bool m_Stopped;
    void Disconnect() override {
        m_Stopped = true;

        if (m_MasterFD == -1)
            return;

        close(m_MasterFD);
        m_PtyReaderThread.Join();
    }

    const char * GetName() override {
        return m_Name.c_str();
    }
    const char * GetDescription() override {
        return m_Description.c_str();
    }

    uint32_t GetVersion() override {
        return m_Version;
    }

    ContextPtr GetPluginContext() const override {
        return m_Context;
    }

    AppConfigPtr GetPluginConfig() const override {
        return m_PluginConfig;
    }

    void InitPlugin(ContextPtr context,
                    AppConfigPtr plugin_config) override {
        m_Context = context;
        m_PluginConfig = plugin_config;
    }
private:
    std::string m_Name;
    std::string m_Description;
    uint32_t m_Version;

protected:
    ContextPtr m_Context;
    AppConfigPtr m_PluginConfig;

    std::shared_ptr<char> m_TermName;
    std::shared_ptr<char> m_CmdLine;
    std::vector<char *> m_Args;

public:
    void BuildEnviron() {
        m_Envs.clear();

        extern char ** environ;

        char ** tmp = environ;

        std::string term_name = "TERM=" + GetPluginContext()->GetAppConfig()->GetEntry("/term/term_name", "xterm-256color");

        m_TermName = {strdup(term_name.c_str()), [](char * data) {
                free(data);
            }};

        bool term_updated = false;
        while(*tmp) {
            if (term_name != "NOT FOUND" && !strncmp(*tmp, "TERM=", strlen("TERM=")))
            {
                m_Envs.push_back(m_TermName.get());
                term_updated = true;
            }
            else
            {
                m_Envs.push_back(*tmp);
            }
            tmp++;
        }

        if (!term_updated) {
            m_Envs.push_back(m_TermName.get());
        }

        m_Envs.push_back(NULL);
    }

    void BuildCmdLine(const std::string & cmd_line)
    {
        m_CmdLine = {
            strdup(cmd_line.c_str()), [](char * data) {
                free(data);
            }};

        char * token = strtok(m_CmdLine.get(), " ");

        m_Args.clear();

        while(token != NULL) {
            m_Args.push_back(token);
            token = strtok(NULL, " ");
        }

        m_Args.push_back(NULL);
    }

    void Connect(const char * host, int port, const char * user_name, const char * password) override {
        (void)host;
        (void)port;
        (void)user_name;
        (void)password;

        m_Stopped = false;

        pid_t pid;
        struct winsize ws {
            (unsigned short)m_Rows,
                    (unsigned short)m_Cols,
                    0,
                    0
                    };

        std::string shell = GetPluginConfig()->GetEntry("shell", "NOT FOUND");

        if (shell == "NOT FOUND")
        {
            char * sys_shell = getenv("SHELL");

            if (sys_shell)
                shell = std::string(sys_shell);
            else
                shell = std::string("/bin/bash -i -l");
        }

        BuildEnviron();

        BuildCmdLine(shell);

        pid = forkpty(&m_MasterFD, NULL, NULL, &ws);

        // impossible to fork
        if (pid < 0) {
            std::cerr << "pty fork failed" << std::endl;
            return;
        }
        // child
        else if (pid == 0) {
#ifdef __APPLE__
            execve(m_Args[0], &m_Args[0], &m_Envs[0]);
#else
            execvpe(m_Args[0], &m_Args[0], &m_Envs[0]);
#endif
        }
        // parent
        else {
            m_PtyPid = pid;
            int flags = fcntl(m_MasterFD, F_GETFL, 0);
            fcntl(m_MasterFD, F_SETFL, flags | O_NONBLOCK);

            m_PtyReaderThread.Start();
        }
    }

    void Send(const std::vector<unsigned char> & data, size_t n) override {
        if (write(m_MasterFD, &data[0], n) <= 0) {
            std::cerr << "write failed:" << strerror(errno) << std::endl;
        }

        if (tcdrain(m_MasterFD))
            std::cerr << "tcdrain failed:" << strerror(errno) << std::endl;
    }

    void Resize(uint32_t row, uint32_t col) override {
        m_Rows = row;
        m_Cols = col;
        /*
          struct winsize {
          unsigned short ws_row;
          unsigned short ws_col;
          unsigned short ws_xpixel;   / unused /
          unsigned short ws_ypixel;   / unused /
          };
        */

        if (m_MasterFD == -1)
            return;

        struct winsize ws {
            (unsigned short)row,
                    (unsigned short)col,
                    0,
                    0
                    };

        int result = ioctl(m_MasterFD, TIOCSWINSZ, &ws);
        if (result) {
            std::cerr << "resize result:" << result << "," << errno
                      << ", " << EINVAL
                      << ", " << ENOTTY
                      << ", " << EPERM
                      << ", " << strerror(errno)
                      << std::endl;
        }
    }

    unsigned long Run(void * /*pArgument*/) override {
        struct timeval tv;

        TermContextPtr context = std::dynamic_pointer_cast<TermContext>(GetPluginContext());

        if (!context)
            return 0;

        TermDataHandlerPtr term_data_handler =
                context->GetTermDataHandler();
        TermWindowPtr term_window =
                context->GetTermWindow();

        for (;;) {

            fd_set          read_fd;
            fd_set          except_fd;

            tv.tv_sec = 1;
            tv.tv_usec = 0;

            FD_ZERO(&read_fd);
            FD_ZERO(&except_fd);

            FD_SET(m_MasterFD, &read_fd);
            FD_SET(m_MasterFD, &except_fd);

            int result = select(m_MasterFD+1, &read_fd, NULL, &except_fd, &tv);

            if (m_Stopped)
                break;

            if (result == -1) {
                if (errno == EINTR) {
                    continue;
                }

                std::cerr << "select failed with err:" << errno << std::endl;
                break;
            } else if (result == 0) {
                //timeout
                continue;
            }

            if (FD_ISSET(m_MasterFD, &except_fd))
            {
                term_window->Close();
                break;
            }

            if (FD_ISSET(m_MasterFD, &read_fd))
            {
                int count = read(m_MasterFD, &m_ReadBuffer[0], m_ReadBuffer.size());
                if (count == -1) {
                    if (errno == EINTR)
                        continue;

                    std::cerr << "read failed\n" << std::endl;
                    term_window->Close();
                    break;
                }

                if (count > 0) {
                    term_data_handler->OnData(m_ReadBuffer, count);
                }
            }
        }
        return 0;
    }
private:
    uint32_t m_Rows;
    uint32_t m_Cols;
    int m_MasterFD;
    std::vector<unsigned char> m_ReadBuffer;
    PortableThread::CPortableThread m_PtyReaderThread;
    std::vector<char *> m_Envs;
    pid_t m_PtyPid;
};

void delete_data(void * data) {
    delete (Plugin*)data;
}

extern "C"
void register_plugins(PluginManagerPtr plugin_manager) {
    plugin_manager->RegisterPlugin(PluginPtr {new TermNetworkPty, delete_data});;
}
<|endoftext|>