<commit_before>/* Copyright 2021 The TensorFlow 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.

==============================================================================*/

#include <algorithm>

#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/PassDetail.h"
#include "mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Value.h"
#include "mlir/Pass/Pass.h"

namespace mlir {
namespace mhlo {
namespace {

// To avoid duplicate broadcasts, we collect all the intended broadcasts ahead
// of realizing any broadcasts in the IR. These are broadcasted versions of
// values that we are interested in, and they are uniquely characterized by a
// `BroadcastIntent` value.
struct BroadcastIntent {
  RankedTensorType result_type;
  Value target_value;
  Value output_dimensions;
  Attribute broadcast_dimensions;
  bool operator==(BroadcastIntent rhs) const {
    return result_type == rhs.result_type && target_value == rhs.target_value &&
           output_dimensions == rhs.output_dimensions &&
           broadcast_dimensions == rhs.broadcast_dimensions;
  }
  bool operator!=(BroadcastIntent rhs) const { return !(*this == rhs); }
};

}  // namespace
}  // namespace mhlo
}  // namespace mlir

namespace llvm {

template <>
struct DenseMapInfo<mlir::mhlo::BroadcastIntent> {
  static mlir::mhlo::BroadcastIntent getEmptyKey() {
    return {DenseMapInfo<mlir::RankedTensorType>::getEmptyKey(),
            DenseMapInfo<mlir::Value>::getEmptyKey(),
            DenseMapInfo<mlir::Value>::getEmptyKey(),
            DenseMapInfo<mlir::Attribute>::getEmptyKey()};
  }
  static mlir::mhlo::BroadcastIntent getTombstoneKey() {
    return {DenseMapInfo<mlir::RankedTensorType>::getTombstoneKey(),
            DenseMapInfo<mlir::Value>::getTombstoneKey(),
            DenseMapInfo<mlir::Value>::getTombstoneKey(),
            DenseMapInfo<mlir::Attribute>::getTombstoneKey()};
  }
  static unsigned getHashValue(const mlir::mhlo::BroadcastIntent &intent) {
    return hash_combine(
        DenseMapInfo<mlir::RankedTensorType>::getHashValue(intent.result_type),
        DenseMapInfo<mlir::Value>::getHashValue(intent.target_value),
        DenseMapInfo<mlir::Value>::getHashValue(intent.output_dimensions),
        DenseMapInfo<mlir::Attribute>::getHashValue(
            intent.broadcast_dimensions));
  }
  static bool isEqual(const mlir::mhlo::BroadcastIntent &lhs,
                      const mlir::mhlo::BroadcastIntent &rhs) {
    return lhs == rhs;
  }
};

}  // namespace llvm

namespace mlir {
namespace mhlo {
namespace {

bool AllowsForBroadcastPropagation(Operation *op) {
  if (op->hasTrait<mlir::OpTrait::SameOperandsAndResultShape>() &&
      op->hasTrait<mlir::OpTrait::Elementwise>() && op->getNumResults() == 1) {
    return true;
  }
  if (op->hasTrait<mlir::mhlo::OpTrait::BroadcastingElementwise>() &&
      op->getNumResults() == 1) {
    return true;
  }
  return false;
}

void TransitivelyEraseUnusedSideEffectFreeOps(Operation *root) {
  SmallPtrSet<Operation *, 16> ops_to_erase;
  SmallVector<Operation *, 16> ops_to_erase_ordered;

  // Find all the ops to erase.
  SmallVector<Operation *> worklist = {root};
  while (!worklist.empty()) {
    Operation *op = worklist.back();
    worklist.pop_back();

    // Erase ops only once.
    if (ops_to_erase.count(op)) continue;

    // Erase only operations that are unused and free of side effects.
    if (!MemoryEffectOpInterface::hasNoEffect(op) ||
        !llvm::all_of(op->getUsers(), [&](Operation *user) {
          return ops_to_erase.count(user);
        })) {
      continue;
    }

    // Erase and "recur".
    ops_to_erase.insert(op);
    ops_to_erase_ordered.push_back(op);
    for (Value operand : op->getOperands()) {
      if (Operation *def = operand.getDefiningOp()) worklist.push_back(def);
    }
  }

  // Finally, erase the ops.
  for (Operation *op : ops_to_erase_ordered) op->erase();
}

bool IsAvailableAt(Value value, Operation *op) {
  if (Operation *def = value.getDefiningOp())
    return def->getBlock() == op->getBlock() && def->isBeforeInBlock(op);
  return value.cast<BlockArgument>().getParentBlock() == op->getBlock();
}

// Assumes that all values are defined within the block or dominate the block.
void SetInsertionPointToEarliestPointWithAllValuesAvailable(OpBuilder &b,
                                                            Block *block,
                                                            ValueRange values) {
  Operation *last_def = nullptr;
  for (Value v : values) {
    Operation *def = v.getDefiningOp();
    if (def && def->getBlock() == block) {
      if (!last_def || last_def->isBeforeInBlock(def)) last_def = def;
    }
  }
  if (last_def) {
    b.setInsertionPointAfter(last_def);
  } else {
    b.setInsertionPointToStart(block);
  }
}

void PropagateBroadcast(DynamicBroadcastInDimOp root) {
  OpBuilder builder(root.getContext());
  BroadcastIntent root_bcast_intent = {
      root.getResult().getType().cast<RankedTensorType>(), root.operand(),
      root.output_dimensions(), root.broadcast_dimensions()};

  // We can move broadcasts up over (broadcasting) element-wise operations and
  // propagate them through the IR to perform them early. Instead of
  // broadcasting the result of such an op, we can broadcast the operands and
  // apply the element-wise operation to them.
  //
  // To avoid exponential growth of the IR, we will do this in two phases:
  //   1) First, we collect all the unique broadcast intents. These are
  //      broadcasted versions of values that we are interested in. They may
  //      later be materialized as an explicit broadcast or they can be the
  //      direct result of an operation over which a broadcast was propagated.
  //   2) Then, we fulfill every broadcast intent in reverse topological order
  //      to ensure that their dependencies (the broadcasted operands) are
  //      available.

  // Collect all the broadcast intents, starting with the root. Record
  // dependencies for later lookups.
  DenseSet<BroadcastIntent> bcast_intents = {root_bcast_intent};
  SmallVector<BroadcastIntent> bcast_intents_ordered = {root_bcast_intent};
  DenseMap<BroadcastIntent, SmallVector<BroadcastIntent>>
      bcast_propagation_dependencies;
  Block *the_block = root->getBlock();

  // We use the ordered broadcast intents as a worklist, the first `i` intents
  // of which have been processed.
  auto empty_broadcast_dimensions = builder.getI64TensorAttr({});
  for (int i = 0; i < bcast_intents_ordered.size(); ++i) {
    BroadcastIntent it = bcast_intents_ordered[i];
    Operation *producer_op = it.target_value.getDefiningOp();

    // We can propagate broadcasts over (broadcasting) element-wise operations
    // with the restriction that they must be in the same block as they may
    // depend on assumptions.
    if (producer_op && producer_op->getBlock() == the_block &&
        AllowsForBroadcastPropagation(producer_op)) {
      // Collect this broadcast propagation's dependencies: the broadcasted
      // versions of the operands that we will need in the second phase.
      SmallVector<BroadcastIntent> dependencies;
      for (auto operand : producer_op->getOperands()) {
        auto operand_ty = operand.getType().cast<RankedTensorType>();
        auto operand_broadcast_dimensions = operand_ty.getRank() == 0
                                                ? empty_broadcast_dimensions
                                                : it.broadcast_dimensions;
        auto bcasted_operand_ty = RankedTensorType::get(
            it.result_type.getShape(), operand_ty.getElementType());
        BroadcastIntent bcasted_operand_intent = {bcasted_operand_ty, operand,
                                                  it.output_dimensions,
                                                  operand_broadcast_dimensions};
        dependencies.push_back(bcasted_operand_intent);

        // If this broadcast intent was not yet seen, add it to the worklist.
        // Otherwise, we know it will be fulfilled earlier.
        if (!bcast_intents.count(bcasted_operand_intent)) {
          bcast_intents_ordered.push_back(bcasted_operand_intent);
          bcast_intents.insert(bcasted_operand_intent);
        }
      }
      bcast_propagation_dependencies[it] = dependencies;
    }
  }

  // Realize all the broadcast intents in reverse topological order of the
  // producer ops. We can use the positions in the block for this. All broadcast
  // intents outside the block (e.g. arguments) will be sorted towards the
  // front.
  // This ordering is independent of the output dimensions as dependencies can
  // only occur between broadcast intents of the same output dimension.
  DenseMap<BroadcastIntent, Value> realizations;
  std::sort(bcast_intents_ordered.begin(), bcast_intents_ordered.end(),
            [&](const BroadcastIntent &a, const BroadcastIntent &b) {
              Operation *producer_op_a = a.target_value.getDefiningOp();
              Operation *producer_op_b = b.target_value.getDefiningOp();
              bool a_in_block =
                  producer_op_a && producer_op_a->getBlock() == the_block;
              bool b_in_block =
                  producer_op_b && producer_op_b->getBlock() == the_block;
              if (a_in_block && b_in_block) {
                return producer_op_a->isBeforeInBlock(producer_op_b);
              }
              return !a_in_block && b_in_block;
            });
  for (auto it : bcast_intents_ordered) {
    Operation *producer_op = it.target_value.getDefiningOp();

    // Realize broadcast intent for an element-wise operation based on the
    // broadcasted operands, if possible.
    if (bcast_propagation_dependencies.count(it)) {
      assert(producer_op && producer_op->getBlock() == the_block &&
             AllowsForBroadcastPropagation(producer_op) &&
             "expect (broadcasting)  element-wise op in the same block");
      auto bcasted_operands =
          llvm::to_vector(llvm::map_range(bcast_propagation_dependencies[it],
                                          [&](BroadcastIntent operand_intent) {
                                            return realizations[operand_intent];
                                          }));
      SetInsertionPointToEarliestPointWithAllValuesAvailable(builder, the_block,
                                                             bcasted_operands);
      OperationState new_producer_op_state(
          producer_op->getLoc(), producer_op->getName().getStringRef(),
          bcasted_operands, it.result_type, producer_op->getAttrs());
      Operation *new_producer_op =
          builder.createOperation(new_producer_op_state);
      assert(new_producer_op->getNumResults() == 1 &&
             "expect exactly one result");
      realizations[it] = new_producer_op->getResults().front();
      continue;
    }

    // Fall back to explicit broadcasts, otherwise.
    SetInsertionPointToEarliestPointWithAllValuesAvailable(
        builder, the_block, ValueRange{it.target_value, it.output_dimensions});
    realizations[it] = builder.create<DynamicBroadcastInDimOp>(
        it.target_value.getLoc(), it.result_type, it.target_value,
        it.output_dimensions,
        it.broadcast_dimensions.cast<DenseIntElementsAttr>());
  }

  // Lookup the replacement for the root operation.
  auto replacement = realizations[root_bcast_intent];
  root->replaceAllUsesWith(ValueRange{replacement});

  // Erase all the operations that have become redundant as a result of this
  // rewrite.
  TransitivelyEraseUnusedSideEffectFreeOps(root);
}

struct BroadcastPropagationPass
    : public BroadcastPropagationPassBase<BroadcastPropagationPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<mhlo::MhloDialect>();
  }

  void runOnOperation() override {
    getOperation().walk(
        [&](DynamicBroadcastInDimOp bcast) { PropagateBroadcast(bcast); });
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createBroadcastPropagationPass() {
  return std::make_unique<BroadcastPropagationPass>();
}

}  // namespace mhlo
}  // namespace mlir
<commit_msg>[MHLO] Address clang tidy concerns<commit_after>/* Copyright 2021 The TensorFlow 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.

==============================================================================*/

#include <algorithm>

#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/PassDetail.h"
#include "mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Value.h"
#include "mlir/Pass/Pass.h"

namespace mlir {
namespace mhlo {
namespace {

// To avoid duplicate broadcasts, we collect all the intended broadcasts ahead
// of realizing any broadcasts in the IR. These are broadcasted versions of
// values that we are interested in, and they are uniquely characterized by a
// `BroadcastIntent` value.
struct BroadcastIntent {
  RankedTensorType result_type;
  Value target_value;
  Value output_dimensions;
  Attribute broadcast_dimensions;
  bool operator==(BroadcastIntent rhs) const {
    return result_type == rhs.result_type && target_value == rhs.target_value &&
           output_dimensions == rhs.output_dimensions &&
           broadcast_dimensions == rhs.broadcast_dimensions;
  }
  bool operator!=(BroadcastIntent rhs) const { return !(*this == rhs); }
};

}  // namespace
}  // namespace mhlo
}  // namespace mlir

namespace llvm {

template <>
struct DenseMapInfo<mlir::mhlo::BroadcastIntent> {
  static mlir::mhlo::BroadcastIntent getEmptyKey() {
    return {DenseMapInfo<mlir::RankedTensorType>::getEmptyKey(),
            DenseMapInfo<mlir::Value>::getEmptyKey(),
            DenseMapInfo<mlir::Value>::getEmptyKey(),
            DenseMapInfo<mlir::Attribute>::getEmptyKey()};
  }
  static mlir::mhlo::BroadcastIntent getTombstoneKey() {
    return {DenseMapInfo<mlir::RankedTensorType>::getTombstoneKey(),
            DenseMapInfo<mlir::Value>::getTombstoneKey(),
            DenseMapInfo<mlir::Value>::getTombstoneKey(),
            DenseMapInfo<mlir::Attribute>::getTombstoneKey()};
  }
  static unsigned getHashValue(const mlir::mhlo::BroadcastIntent &intent) {
    return hash_combine(
        DenseMapInfo<mlir::RankedTensorType>::getHashValue(intent.result_type),
        DenseMapInfo<mlir::Value>::getHashValue(intent.target_value),
        DenseMapInfo<mlir::Value>::getHashValue(intent.output_dimensions),
        DenseMapInfo<mlir::Attribute>::getHashValue(
            intent.broadcast_dimensions));
  }
  static bool isEqual(const mlir::mhlo::BroadcastIntent &lhs,
                      const mlir::mhlo::BroadcastIntent &rhs) {
    return lhs == rhs;
  }
};

}  // namespace llvm

namespace mlir {
namespace mhlo {
namespace {

bool AllowsForBroadcastPropagation(Operation *op) {
  if (op->hasTrait<mlir::OpTrait::SameOperandsAndResultShape>() &&
      op->hasTrait<mlir::OpTrait::Elementwise>() && op->getNumResults() == 1) {
    return true;
  }
  if (op->hasTrait<mlir::mhlo::OpTrait::BroadcastingElementwise>() &&
      op->getNumResults() == 1) {
    return true;
  }
  return false;
}

void TransitivelyEraseUnusedSideEffectFreeOps(Operation *root) {
  SmallPtrSet<Operation *, 16> ops_to_erase;
  SmallVector<Operation *, 16> ops_to_erase_ordered;

  // Find all the ops to erase.
  SmallVector<Operation *> worklist = {root};
  while (!worklist.empty()) {
    Operation *op = worklist.back();
    worklist.pop_back();

    // Erase ops only once.
    if (ops_to_erase.count(op)) continue;

    // Erase only operations that are unused and free of side effects.
    if (!MemoryEffectOpInterface::hasNoEffect(op) ||
        !llvm::all_of(op->getUsers(), [&](Operation *user) {
          return ops_to_erase.count(user);
        })) {
      continue;
    }

    // Erase and "recur".
    ops_to_erase.insert(op);
    ops_to_erase_ordered.push_back(op);
    for (Value operand : op->getOperands()) {
      if (Operation *def = operand.getDefiningOp()) worklist.push_back(def);
    }
  }

  // Finally, erase the ops.
  for (Operation *op : ops_to_erase_ordered) op->erase();
}

bool IsAvailableAt(Value value, Operation *op) {
  if (Operation *def = value.getDefiningOp())
    return def->getBlock() == op->getBlock() && def->isBeforeInBlock(op);
  return value.cast<BlockArgument>().getParentBlock() == op->getBlock();
}

// Assumes that all values are defined within the block or dominate the block.
void SetInsertionPointToEarliestPointWithAllValuesAvailable(OpBuilder &b,
                                                            Block *block,
                                                            ValueRange values) {
  Operation *last_def = nullptr;
  for (Value v : values) {
    Operation *def = v.getDefiningOp();
    if (def && def->getBlock() == block) {
      if (!last_def || last_def->isBeforeInBlock(def)) last_def = def;
    }
  }
  if (last_def) {
    b.setInsertionPointAfter(last_def);
  } else {
    b.setInsertionPointToStart(block);
  }
}

void PropagateBroadcast(DynamicBroadcastInDimOp root) {
  OpBuilder builder(root.getContext());
  BroadcastIntent root_bcast_intent = {
      root.getResult().getType().cast<RankedTensorType>(), root.operand(),
      root.output_dimensions(), root.broadcast_dimensions()};

  // We can move broadcasts up over (broadcasting) element-wise operations and
  // propagate them through the IR to perform them early. Instead of
  // broadcasting the result of such an op, we can broadcast the operands and
  // apply the element-wise operation to them.
  //
  // To avoid exponential growth of the IR, we will do this in two phases:
  //   1) First, we collect all the unique broadcast intents. These are
  //      broadcasted versions of values that we are interested in. They may
  //      later be materialized as an explicit broadcast or they can be the
  //      direct result of an operation over which a broadcast was propagated.
  //   2) Then, we fulfill every broadcast intent in reverse topological order
  //      to ensure that their dependencies (the broadcasted operands) are
  //      available.

  // Collect all the broadcast intents, starting with the root. Record
  // dependencies for later lookups.
  DenseSet<BroadcastIntent> bcast_intents = {root_bcast_intent};
  SmallVector<BroadcastIntent> bcast_intents_ordered = {root_bcast_intent};
  DenseMap<BroadcastIntent, SmallVector<BroadcastIntent>>
      bcast_propagation_dependencies;
  Block *the_block = root->getBlock();

  // We use the ordered broadcast intents as a worklist, the first `i` intents
  // of which have been processed.
  auto empty_broadcast_dimensions = builder.getI64TensorAttr({});
  for (int i = 0; i < bcast_intents_ordered.size(); ++i) {
    BroadcastIntent it = bcast_intents_ordered[i];
    Operation *producer_op = it.target_value.getDefiningOp();

    // We can propagate broadcasts over (broadcasting) element-wise operations
    // with the restriction that they must be in the same block as they may
    // depend on assumptions.
    if (producer_op && producer_op->getBlock() == the_block &&
        AllowsForBroadcastPropagation(producer_op)) {
      // Collect this broadcast propagation's dependencies: the broadcasted
      // versions of the operands that we will need in the second phase.
      SmallVector<BroadcastIntent> dependencies;
      for (auto operand : producer_op->getOperands()) {
        auto operand_ty = operand.getType().cast<RankedTensorType>();
        auto operand_broadcast_dimensions = operand_ty.getRank() == 0
                                                ? empty_broadcast_dimensions
                                                : it.broadcast_dimensions;
        auto bcasted_operand_ty = RankedTensorType::get(
            it.result_type.getShape(), operand_ty.getElementType());
        BroadcastIntent bcasted_operand_intent = {bcasted_operand_ty, operand,
                                                  it.output_dimensions,
                                                  operand_broadcast_dimensions};
        dependencies.push_back(bcasted_operand_intent);

        // If this broadcast intent was not yet seen, add it to the worklist.
        // Otherwise, we know it will be fulfilled earlier.
        if (!bcast_intents.count(bcasted_operand_intent)) {
          bcast_intents_ordered.push_back(bcasted_operand_intent);
          bcast_intents.insert(bcasted_operand_intent);
        }
      }
      bcast_propagation_dependencies[it] = dependencies;
    }
  }

  // Realize all the broadcast intents in reverse topological order of the
  // producer ops. We can use the positions in the block for this. All broadcast
  // intents outside the block (e.g. arguments) will be sorted towards the
  // front.
  // This ordering is independent of the output dimensions as dependencies can
  // only occur between broadcast intents of the same output dimension.
  DenseMap<BroadcastIntent, Value> realizations;
  std::sort(bcast_intents_ordered.begin(), bcast_intents_ordered.end(),
            [&](const BroadcastIntent &a, const BroadcastIntent &b) {
              Operation *producer_op_a = a.target_value.getDefiningOp();
              Operation *producer_op_b = b.target_value.getDefiningOp();
              bool a_in_block = producer_op_a != nullptr &&
                                producer_op_a->getBlock() == the_block;
              bool b_in_block = producer_op_b != nullptr &&
                                producer_op_b->getBlock() == the_block;
              if (a_in_block && b_in_block) {
                return producer_op_a->isBeforeInBlock(producer_op_b);
              }
              return !a_in_block && b_in_block;
            });
  for (auto it : bcast_intents_ordered) {
    Operation *producer_op = it.target_value.getDefiningOp();

    // Realize broadcast intent for an element-wise operation based on the
    // broadcasted operands, if possible.
    if (bcast_propagation_dependencies.count(it)) {
      assert(producer_op && producer_op->getBlock() == the_block &&
             AllowsForBroadcastPropagation(producer_op) &&
             "expect (broadcasting)  element-wise op in the same block");
      auto bcasted_operands =
          llvm::to_vector(llvm::map_range(bcast_propagation_dependencies[it],
                                          [&](BroadcastIntent operand_intent) {
                                            return realizations[operand_intent];
                                          }));
      SetInsertionPointToEarliestPointWithAllValuesAvailable(builder, the_block,
                                                             bcasted_operands);
      OperationState new_producer_op_state(
          producer_op->getLoc(), producer_op->getName().getStringRef(),
          bcasted_operands, it.result_type, producer_op->getAttrs());
      Operation *new_producer_op =
          builder.createOperation(new_producer_op_state);
      assert(new_producer_op->getNumResults() == 1 &&
             "expect exactly one result");
      realizations[it] = new_producer_op->getResults().front();
      continue;
    }

    // Fall back to explicit broadcasts, otherwise.
    SetInsertionPointToEarliestPointWithAllValuesAvailable(
        builder, the_block, ValueRange{it.target_value, it.output_dimensions});
    realizations[it] = builder.create<DynamicBroadcastInDimOp>(
        it.target_value.getLoc(), it.result_type, it.target_value,
        it.output_dimensions,
        it.broadcast_dimensions.cast<DenseIntElementsAttr>());
  }

  // Lookup the replacement for the root operation.
  auto replacement = realizations[root_bcast_intent];
  root->replaceAllUsesWith(ValueRange{replacement});

  // Erase all the operations that have become redundant as a result of this
  // rewrite.
  TransitivelyEraseUnusedSideEffectFreeOps(root);
}

struct BroadcastPropagationPass
    : public BroadcastPropagationPassBase<BroadcastPropagationPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<mhlo::MhloDialect>();
  }

  void runOnOperation() override {
    getOperation().walk(
        [&](DynamicBroadcastInDimOp bcast) { PropagateBroadcast(bcast); });
  }
};

}  // namespace

std::unique_ptr<OperationPass<FuncOp>> createBroadcastPropagationPass() {
  return std::make_unique<BroadcastPropagationPass>();
}

}  // namespace mhlo
}  // namespace mlir
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName      :    NFCProxyServerNet_ClientModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2013-05-06
//    @Module           :    NFCProxyServerNet_ClientModule
//
// -------------------------------------------------------------------------

//#include "stdafx.h"
#include "NFCProxyServerToGameModule.h"
#include "NFProxyServerNet_ClientPlugin.h"
#include "NFComm/NFCore/NFIHeartBeatManager.h"
#include "NFComm/NFCore/NFCHeartBeatManager.h"
#include "NFComm/NFPluginModule/NFILogicClassModule.h"

bool NFCProxyServerToGameModule::Init()
{
    return true;
}

bool NFCProxyServerToGameModule::Shut()
{
    //Final();
    //Clear();
    return true;
}

bool NFCProxyServerToGameModule::Execute(const float fLasFrametime, const float fStartedTime)
{
	return NFIClusterClientModule::Execute(fLasFrametime, fStartedTime);
}

bool NFCProxyServerToGameModule::AfterInit()
{

    m_pEventProcessModule = dynamic_cast<NFIEventProcessModule*>(pPluginManager->FindModule("NFCEventProcessModule"));
    m_pProxyLogicModule = dynamic_cast<NFIProxyLogicModule*>(pPluginManager->FindModule("NFCProxyLogicModule"));
    m_pKernelModule = dynamic_cast<NFIKernelModule*>(pPluginManager->FindModule("NFCKernelModule"));
    m_pProxyServerNet_ServerModule = dynamic_cast<NFIProxyServerNet_ServerModule*>(pPluginManager->FindModule("NFCProxyServerNet_ServerModule"));
    m_pElementInfoModule = dynamic_cast<NFIElementInfoModule*>(pPluginManager->FindModule("NFCElementInfoModule"));
	m_pLogModule = dynamic_cast<NFILogModule*>(pPluginManager->FindModule("NFCLogModule"));
	m_pLogicClassModule = dynamic_cast<NFILogicClassModule*>(pPluginManager->FindModule("NFCLogicClassModule"));

    assert(NULL != m_pEventProcessModule);
    assert(NULL != m_pProxyLogicModule);
    assert(NULL != m_pKernelModule);
    assert(NULL != m_pProxyServerNet_ServerModule);
    assert(NULL != m_pElementInfoModule);
	assert(NULL != m_pLogModule);
	assert(NULL != m_pLogicClassModule);

	NFIClusterClientModule::Bind(this, &NFCProxyServerToGameModule::OnReciveGSPack, &NFCProxyServerToGameModule::OnSocketGSEvent);

	NF_SHARE_PTR<NFILogicClass> xLogicClass = m_pLogicClassModule->GetElement("Server");
	if (xLogicClass.get())
	{
		NFList<std::string>& xNameList = xLogicClass->GetConfigNameList();
		std::string strConfigName;
		for (bool bRet = xNameList.First(strConfigName); bRet; bRet = xNameList.Next(strConfigName))
		{
			const int nServerType = m_pElementInfoModule->GetPropertyInt(strConfigName, "Type");
            const int nServerID = m_pElementInfoModule->GetPropertyInt(strConfigName, "ServerID");
            if (nServerType == NF_SERVER_TYPES::NF_ST_GAME)
			{
				const int nPort = m_pElementInfoModule->GetPropertyInt(strConfigName, "Port");
				const int nMaxConnect = m_pElementInfoModule->GetPropertyInt(strConfigName, "MaxOnline");
				const int nCpus = m_pElementInfoModule->GetPropertyInt(strConfigName, "CpuCount");
				const std::string& strName = m_pElementInfoModule->GetPropertyString(strConfigName, "Name");
				const std::string& strIP = m_pElementInfoModule->GetPropertyString(strConfigName, "IP");

				ServerData xServerData;

				xServerData.nGameID = nServerID;
				xServerData.eServerType = (NF_SERVER_TYPE)nServerType;
				xServerData.strIP = strIP;
				xServerData.nPort = nPort;
				xServerData.strName = strName;
				xServerData.eState = NFMsg::EServerState::EST_MAINTEN;

				NFIClusterClientModule::AddServer(xServerData);
			}
		}
	}

    return true;
}

int NFCProxyServerToGameModule::OnReciveGSPack( const NFIPacket& msg )
{
	switch (msg.GetMsgHead()->GetMsgID())
	{
	case NFMsg::EGMI_ACK_ENTER_GAME:
	    OnAckEnterGame(msg);
	    break;
	default:
	    m_pProxyServerNet_ServerModule->Transpond(msg);
	    break;
	}

	return 0;
}

int NFCProxyServerToGameModule::OnSocketGSEvent( const int nSockIndex, const NF_NET_EVENT eEvent, NFINet* pNet )
{
	if (eEvent & NF_NET_EVENT_EOF)
	{
	}
	else if (eEvent & NF_NET_EVENT_ERROR)
	{
	}
	else if (eEvent & NF_NET_EVENT_TIMEOUT)
	{
	}
	else  if (eEvent == NF_NET_EVENT_CONNECTED)
	{
	    m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(0, nSockIndex), "NF_NET_EVENT_CONNECTED", "connectioned success", __FUNCTION__, __LINE__);
	    Register(pNet);

	}
	return 0;
}

void NFCProxyServerToGameModule::Register(NFINet* pNet)
{
	NF_SHARE_PTR<NFILogicClass> xLogicClass = m_pLogicClassModule->GetElement("Server");
	if (xLogicClass.get())
	{
		NFList<std::string>& xNameList = xLogicClass->GetConfigNameList();
		std::string strConfigName;
		for (bool bRet = xNameList.First(strConfigName); bRet; bRet = xNameList.Next(strConfigName))
		{
			const int nServerType = m_pElementInfoModule->GetPropertyInt(strConfigName, "Type");
            const int nServerID = m_pElementInfoModule->GetPropertyInt(strConfigName, "ServerID");
            if (nServerType == NF_SERVER_TYPES::NF_ST_PROXY && pPluginManager->AppID() == nServerID)
			{
				const int nPort = m_pElementInfoModule->GetPropertyInt(strConfigName, "Port");
				const int nMaxConnect = m_pElementInfoModule->GetPropertyInt(strConfigName, "MaxOnline");
				const int nCpus = m_pElementInfoModule->GetPropertyInt(strConfigName, "CpuCount");
				const std::string& strName = m_pElementInfoModule->GetPropertyString(strConfigName, "Name");
				const std::string& strIP = m_pElementInfoModule->GetPropertyString(strConfigName, "IP");

				NFMsg::ServerInfoReportList xMsg;
				NFMsg::ServerInfoReport* pData = xMsg.add_server_list();

				pData->set_server_id(nServerID);
				pData->set_server_name(strName);
				pData->set_server_cur_count(0);
				pData->set_server_ip(strIP);
				pData->set_server_port(nPort);
				pData->set_server_max_online(nMaxConnect);
				pData->set_server_state(NFMsg::EST_NARMAL);
				pData->set_server_type(nServerType);

				NF_SHARE_PTR<ServerData> pServerData = GetServerNetInfo(pNet);
				if (pServerData)
				{
					int nTargetID = pServerData->nGameID;
					SendToServerByPB(nTargetID, NFMsg::EGameMsgID::EGMI_PTWG_PROXY_REGISTERED, xMsg);

					m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(0, pData->server_id()), pData->server_name(), "Register");
				}
			}
		}
	}
}

void NFCProxyServerToGameModule::OnAckEnterGame(const NFIPacket& msg)
{
    NFIDENTID nPlayerID;
    NFMsg::AckEventResult xData;
    if (!NFINetModule::RecivePB(msg, xData, nPlayerID))
    {
        return;
    }

    if (xData.event_code() == NFMsg::EGEC_ENTER_GAME_SUCCESS)
    {
        const NFIDENTID& xClient = NFINetModule::PBToNF(xData.event_client());
        const NFIDENTID& xPlayer = NFINetModule::PBToNF(xData.event_object());

        m_pProxyServerNet_ServerModule->EnterGameSuccessEvent(xClient, nPlayerID);
    }
}

void NFCProxyServerToGameModule::LogServerInfo( const std::string& strServerInfo )
{
	m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(), strServerInfo, "");
}
<commit_msg>fix offline bug<commit_after>// -------------------------------------------------------------------------
//    @FileName      :    NFCProxyServerNet_ClientModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2013-05-06
//    @Module           :    NFCProxyServerNet_ClientModule
//
// -------------------------------------------------------------------------

//#include "stdafx.h"
#include "NFCProxyServerToGameModule.h"
#include "NFProxyServerNet_ClientPlugin.h"
#include "NFComm/NFCore/NFIHeartBeatManager.h"
#include "NFComm/NFCore/NFCHeartBeatManager.h"
#include "NFComm/NFPluginModule/NFILogicClassModule.h"

bool NFCProxyServerToGameModule::Init()
{
    return true;
}

bool NFCProxyServerToGameModule::Shut()
{
    //Final();
    //Clear();
    return true;
}

bool NFCProxyServerToGameModule::Execute(const float fLasFrametime, const float fStartedTime)
{
	return NFIClusterClientModule::Execute(fLasFrametime, fStartedTime);
}

bool NFCProxyServerToGameModule::AfterInit()
{

    m_pEventProcessModule = dynamic_cast<NFIEventProcessModule*>(pPluginManager->FindModule("NFCEventProcessModule"));
    m_pProxyLogicModule = dynamic_cast<NFIProxyLogicModule*>(pPluginManager->FindModule("NFCProxyLogicModule"));
    m_pKernelModule = dynamic_cast<NFIKernelModule*>(pPluginManager->FindModule("NFCKernelModule"));
    m_pProxyServerNet_ServerModule = dynamic_cast<NFIProxyServerNet_ServerModule*>(pPluginManager->FindModule("NFCProxyServerNet_ServerModule"));
    m_pElementInfoModule = dynamic_cast<NFIElementInfoModule*>(pPluginManager->FindModule("NFCElementInfoModule"));
	m_pLogModule = dynamic_cast<NFILogModule*>(pPluginManager->FindModule("NFCLogModule"));
	m_pLogicClassModule = dynamic_cast<NFILogicClassModule*>(pPluginManager->FindModule("NFCLogicClassModule"));

    assert(NULL != m_pEventProcessModule);
    assert(NULL != m_pProxyLogicModule);
    assert(NULL != m_pKernelModule);
    assert(NULL != m_pProxyServerNet_ServerModule);
    assert(NULL != m_pElementInfoModule);
	assert(NULL != m_pLogModule);
	assert(NULL != m_pLogicClassModule);

	NFIClusterClientModule::Bind(this, &NFCProxyServerToGameModule::OnReciveGSPack, &NFCProxyServerToGameModule::OnSocketGSEvent);

	NF_SHARE_PTR<NFILogicClass> xLogicClass = m_pLogicClassModule->GetElement("Server");
	if (xLogicClass.get())
	{
		NFList<std::string>& xNameList = xLogicClass->GetConfigNameList();
		std::string strConfigName;
		for (bool bRet = xNameList.First(strConfigName); bRet; bRet = xNameList.Next(strConfigName))
		{
			const int nServerType = m_pElementInfoModule->GetPropertyInt(strConfigName, "Type");
            const int nServerID = m_pElementInfoModule->GetPropertyInt(strConfigName, "ServerID");
            if (nServerType == NF_SERVER_TYPES::NF_ST_GAME)
			{
				const int nPort = m_pElementInfoModule->GetPropertyInt(strConfigName, "Port");
				const int nMaxConnect = m_pElementInfoModule->GetPropertyInt(strConfigName, "MaxOnline");
				const int nCpus = m_pElementInfoModule->GetPropertyInt(strConfigName, "CpuCount");
				const std::string& strName = m_pElementInfoModule->GetPropertyString(strConfigName, "Name");
				const std::string& strIP = m_pElementInfoModule->GetPropertyString(strConfigName, "IP");

				ServerData xServerData;

				xServerData.nGameID = nServerID;
				xServerData.eServerType = (NF_SERVER_TYPE)nServerType;
				xServerData.strIP = strIP;
				xServerData.nPort = nPort;
				xServerData.strName = strName;
				xServerData.eState = NFMsg::EServerState::EST_MAINTEN;

				NFIClusterClientModule::AddServer(xServerData);
			}
		}
	}

    return true;
}

int NFCProxyServerToGameModule::OnReciveGSPack( const NFIPacket& msg )
{
	switch (msg.GetMsgHead()->GetMsgID())
	{
	case NFMsg::EGMI_ACK_ENTER_GAME:
	    OnAckEnterGame(msg);
	    break;
	default:
	    m_pProxyServerNet_ServerModule->Transpond(msg);
	    break;
	}

	return 0;
}

int NFCProxyServerToGameModule::OnSocketGSEvent( const int nSockIndex, const NF_NET_EVENT eEvent, NFINet* pNet )
{
	if (eEvent & NF_NET_EVENT_EOF)
	{
	}
	else if (eEvent & NF_NET_EVENT_ERROR)
	{
	}
	else if (eEvent & NF_NET_EVENT_TIMEOUT)
	{
	}
	else  if (eEvent == NF_NET_EVENT_CONNECTED)
	{
	    m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(0, nSockIndex), "NF_NET_EVENT_CONNECTED", "connectioned success", __FUNCTION__, __LINE__);
	    Register(pNet);

	}
	return 0;
}

void NFCProxyServerToGameModule::Register(NFINet* pNet)
{
	NF_SHARE_PTR<NFILogicClass> xLogicClass = m_pLogicClassModule->GetElement("Server");
	if (xLogicClass.get())
	{
		NFList<std::string>& xNameList = xLogicClass->GetConfigNameList();
		std::string strConfigName;
		for (bool bRet = xNameList.First(strConfigName); bRet; bRet = xNameList.Next(strConfigName))
		{
			const int nServerType = m_pElementInfoModule->GetPropertyInt(strConfigName, "Type");
            const int nServerID = m_pElementInfoModule->GetPropertyInt(strConfigName, "ServerID");
            if (nServerType == NF_SERVER_TYPES::NF_ST_PROXY && pPluginManager->AppID() == nServerID)
			{
				const int nPort = m_pElementInfoModule->GetPropertyInt(strConfigName, "Port");
				const int nMaxConnect = m_pElementInfoModule->GetPropertyInt(strConfigName, "MaxOnline");
				const int nCpus = m_pElementInfoModule->GetPropertyInt(strConfigName, "CpuCount");
				const std::string& strName = m_pElementInfoModule->GetPropertyString(strConfigName, "Name");
				const std::string& strIP = m_pElementInfoModule->GetPropertyString(strConfigName, "IP");

				NFMsg::ServerInfoReportList xMsg;
				NFMsg::ServerInfoReport* pData = xMsg.add_server_list();

				pData->set_server_id(nServerID);
				pData->set_server_name(strName);
				pData->set_server_cur_count(0);
				pData->set_server_ip(strIP);
				pData->set_server_port(nPort);
				pData->set_server_max_online(nMaxConnect);
				pData->set_server_state(NFMsg::EST_NARMAL);
				pData->set_server_type(nServerType);

				NF_SHARE_PTR<ServerData> pServerData = GetServerNetInfo(pNet);
				if (pServerData)
				{
					int nTargetID = pServerData->nGameID;
					SendToServerByPB(nTargetID, NFMsg::EGameMsgID::EGMI_PTWG_PROXY_REGISTERED, xMsg);

					m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(0, pData->server_id()), pData->server_name(), "Register");
				}
			}
		}
	}
}

void NFCProxyServerToGameModule::OnAckEnterGame(const NFIPacket& msg)
{
    NFIDENTID nPlayerID;
    NFMsg::AckEventResult xData;
    if (!NFINetModule::RecivePB(msg, xData, nPlayerID))
    {
        return;
    }

    if (xData.event_code() == NFMsg::EGEC_ENTER_GAME_SUCCESS)
    {
        const NFIDENTID& xClient = NFINetModule::PBToNF(xData.event_client());
        const NFIDENTID& xPlayer = NFINetModule::PBToNF(xData.event_object());

        m_pProxyServerNet_ServerModule->EnterGameSuccessEvent(xClient, xPlayer);
    }
}

void NFCProxyServerToGameModule::LogServerInfo( const std::string& strServerInfo )
{
	m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, NFIDENTID(), strServerInfo, "");
}
<|endoftext|>


<commit_before>//----------------------------  logtest.cc  ---------------------------
//    $Id: logtest.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  logtest.cc  ---------------------------

// document crash in deallog related to missing newline

#include "../tests.h"
#include <deal.II/base/logstream.h>
#include <fstream>
#include <iomanip>
#include <limits>

int main()
{
  std::ofstream logfile("log_crash_01/output");
  deallog.attach(logfile);
  deallog.depth_console(0);

  deallog.push("1");
  {
  deallog.threshold_double(1.e-10);
  deallog.push("2");
  deallog << "no newline here!";
  deallog.pop();
  }
}
<commit_msg>simplify test<commit_after>//----------------------------  logtest.cc  ---------------------------
//    $Id: logtest.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  logtest.cc  ---------------------------

// document crash in deallog related to missing newline

#include "../tests.h"
#include <deal.II/base/logstream.h>
#include <fstream>
#include <iomanip>
#include <limits>

int main()
{
  std::ofstream logfile("log_crash_01/output");
  deallog.attach(logfile);
  deallog << "no newline here!";
}
<|endoftext|>


<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

#include <timedb.h>

BOOST_AUTO_TEST_CASE(d_64) {
	// 10 0000 0000
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(1), 257);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(64), 320);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(63), 319);
}

BOOST_AUTO_TEST_CASE(d_256) {
	// 1100 0000 0000
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(256), 3328);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(255), 3327);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(65), 3137);
}

BOOST_AUTO_TEST_CASE(d_2048) {
	// 1110 0000 0000 0000
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(2048), 59392);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(257), 57601);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(4095), 61439);
}

BOOST_AUTO_TEST_CASE(d_big) {
	// 1111 0000 0000 0000 0000
	//      0000 0000 0000 0000
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(2049), 64424511489);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(65535), 64424574975);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(4095), 64424513535);
	BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(4294967295), 68719476735);
}<commit_msg>pedanitc build options<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

#include <timedb.h>

BOOST_AUTO_TEST_CASE(d_64) {
	// 10 0000 0000
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(1), (uint16_t)257);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(64), (uint16_t)320);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_64(63), (uint16_t)319);
}

BOOST_AUTO_TEST_CASE(d_256) {
	// 1100 0000 0000
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(256), (uint16_t)3328);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(255), (uint16_t)3327);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_256(65),  (uint16_t)3137);
}

BOOST_AUTO_TEST_CASE(d_2048) {
	// 1110 0000 0000 0000
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(2048), (uint16_t)59392);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(257),  (uint16_t)57601);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_2048(4095), (uint16_t)61439);
}

BOOST_AUTO_TEST_CASE(d_big) {
	// 1111 0000 0000 0000 0000
	//      0000 0000 0000 0000
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(2049),       (uint64_t)64424511489);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(65535),      (uint64_t)64424574975);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(4095),       (uint64_t)64424513535);
    BOOST_CHECK_EQUAL(timedb::Compression::compress_delta_big(4294967295), (uint64_t)68719476735);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <seastar/core/distributed.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/sstring.hh>
#include <random>

// hack: perf_sstable falsely depends on Boost.Test, but we can't include it with
// with statically linked boost
#define BOOST_REQUIRE(x) (void)(x)
#define BOOST_CHECK_NO_THROW(x) (void)(x)

#include "perf_sstable.hh"

using namespace sstables;

static unsigned iterations = 30;
static unsigned parallelism = 1;

future<> test_write(distributed<test_env>& dt) {
    return seastar::async([&dt] {
        storage_service_for_tests ssft;
        dt.invoke_on_all([] (test_env &t) {
            return t.fill_memtable();
        }).then([&dt] {
            return time_runs(iterations, parallelism, dt, &test_env::flush_memtable);
        }).get();
    });
}

future<> test_compaction(distributed<test_env>& dt) {
    return seastar::async([&dt] {
        storage_service_for_tests ssft;
        dt.invoke_on_all([] (test_env &t) {
            return t.fill_memtable();
        }).then([&dt] {
            return time_runs(iterations, parallelism, dt, &test_env::compaction);
        }).get();
    });
}

future<> test_index_read(distributed<test_env>& dt) {
    return time_runs(iterations, parallelism, dt, &test_env::read_all_indexes);
}

future<> test_sequential_read(distributed<test_env>& dt) {
    return time_runs(iterations, parallelism, dt, &test_env::read_sequential_partitions);
}

enum class test_modes {
    sequential_read,
    index_read,
    write,
    index_write,
    compaction,
};

static std::unordered_map<sstring, test_modes> test_mode = {
    {"sequential_read", test_modes::sequential_read },
    {"index_read", test_modes::index_read },
    {"write", test_modes::write },
    {"index_write", test_modes::index_write },
    {"compaction", test_modes::compaction },
};

int main(int argc, char** argv) {
    namespace bpo = boost::program_options;
    app_template app;
    app.add_options()
        ("parallelism", bpo::value<unsigned>()->default_value(1), "number parallel requests")
        ("iterations", bpo::value<unsigned>()->default_value(30), "number of iterations")
        ("partitions", bpo::value<unsigned>()->default_value(5000000), "number of partitions")
        ("buffer_size", bpo::value<unsigned>()->default_value(64), "sstable buffer size, in KB")
        ("key_size", bpo::value<unsigned>()->default_value(128), "size of partition key")
        ("num_columns", bpo::value<unsigned>()->default_value(5), "number of columns per row")
        ("column_size", bpo::value<unsigned>()->default_value(64), "size in bytes for each column")
        ("sstables", bpo::value<unsigned>()->default_value(1), "number of sstables (valid only for compaction mode)")
        ("mode", bpo::value<sstring>()->default_value("index_write"), "one of: random_read, sequential_read, index_read, write, compaction, index_write (default)")
        ("testdir", bpo::value<sstring>()->default_value("/var/lib/scylla/perf-tests"), "directory in which to store the sstables");

    return app.run_deprecated(argc, argv, [&app] {
        auto test = make_lw_shared<distributed<test_env>>();

        auto cfg = test_env::conf();
        iterations = app.configuration()["iterations"].as<unsigned>();
        parallelism = app.configuration()["parallelism"].as<unsigned>();
        cfg.partitions = app.configuration()["partitions"].as<unsigned>();
        cfg.key_size = app.configuration()["key_size"].as<unsigned>();
        cfg.buffer_size = app.configuration()["buffer_size"].as<unsigned>() << 10;
        cfg.sstables = app.configuration()["sstables"].as<unsigned>();
        sstring dir = app.configuration()["testdir"].as<sstring>();
        cfg.dir = dir;
        auto mode = test_mode[app.configuration()["mode"].as<sstring>()];
        if ((mode == test_modes::index_read) || (mode == test_modes::index_write)) {
            cfg.num_columns = 0;
            cfg.column_size = 0;
        } else {
            cfg.num_columns = app.configuration()["num_columns"].as<unsigned>();
            cfg.column_size = app.configuration()["column_size"].as<unsigned>();
        }
        return test->start(std::move(cfg)).then([mode, dir, test] {
            engine().at_exit([test] { return test->stop(); });
            if ((mode == test_modes::index_read) ||
               (mode == test_modes::sequential_read)) {
                return test->invoke_on_all([] (test_env &t) {
                    return t.load_sstables(iterations);
                }).then_wrapped([] (future<> f) {
                    try {
                        f.get();
                    } catch (...) {
                        std::cerr << "An error occurred when trying to load test sstables. Did you run write mode yet?" << std::endl;
                        throw;
                    }
                });
            } else if ((mode == test_modes::index_write) || (mode == test_modes::write) || (mode == test_modes::compaction)) {
                return test_setup::create_empty_test_dir(dir);
            } else {
                throw std::invalid_argument("Invalid mode");
            }
        }).then([test, mode] {
            if (mode == test_modes::index_read) {
                return test_index_read(*test).then([test] {});
            } else if (mode == test_modes::sequential_read) {
                return test_sequential_read(*test).then([test] {});
            } else if ((mode == test_modes::index_write) || (mode == test_modes::write)) {
                return test_write(*test).then([test] {});
            } else if (mode == test_modes::compaction) {
                return test_compaction(*test).then([test] {});
            } else {
                throw std::invalid_argument("Invalid mode");
            }
        }).then([] {
            return engine().exit(0);
        }).or_terminate();
    });
}
<commit_msg>tests: Drop the unsupported random_read mode in perf_sstable<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <seastar/core/distributed.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/sstring.hh>
#include <random>

// hack: perf_sstable falsely depends on Boost.Test, but we can't include it with
// with statically linked boost
#define BOOST_REQUIRE(x) (void)(x)
#define BOOST_CHECK_NO_THROW(x) (void)(x)

#include "perf_sstable.hh"

using namespace sstables;

static unsigned iterations = 30;
static unsigned parallelism = 1;

future<> test_write(distributed<test_env>& dt) {
    return seastar::async([&dt] {
        storage_service_for_tests ssft;
        dt.invoke_on_all([] (test_env &t) {
            return t.fill_memtable();
        }).then([&dt] {
            return time_runs(iterations, parallelism, dt, &test_env::flush_memtable);
        }).get();
    });
}

future<> test_compaction(distributed<test_env>& dt) {
    return seastar::async([&dt] {
        storage_service_for_tests ssft;
        dt.invoke_on_all([] (test_env &t) {
            return t.fill_memtable();
        }).then([&dt] {
            return time_runs(iterations, parallelism, dt, &test_env::compaction);
        }).get();
    });
}

future<> test_index_read(distributed<test_env>& dt) {
    return time_runs(iterations, parallelism, dt, &test_env::read_all_indexes);
}

future<> test_sequential_read(distributed<test_env>& dt) {
    return time_runs(iterations, parallelism, dt, &test_env::read_sequential_partitions);
}

enum class test_modes {
    sequential_read,
    index_read,
    write,
    index_write,
    compaction,
};

static std::unordered_map<sstring, test_modes> test_mode = {
    {"sequential_read", test_modes::sequential_read },
    {"index_read", test_modes::index_read },
    {"write", test_modes::write },
    {"index_write", test_modes::index_write },
    {"compaction", test_modes::compaction },
};

int main(int argc, char** argv) {
    namespace bpo = boost::program_options;
    app_template app;
    app.add_options()
        ("parallelism", bpo::value<unsigned>()->default_value(1), "number parallel requests")
        ("iterations", bpo::value<unsigned>()->default_value(30), "number of iterations")
        ("partitions", bpo::value<unsigned>()->default_value(5000000), "number of partitions")
        ("buffer_size", bpo::value<unsigned>()->default_value(64), "sstable buffer size, in KB")
        ("key_size", bpo::value<unsigned>()->default_value(128), "size of partition key")
        ("num_columns", bpo::value<unsigned>()->default_value(5), "number of columns per row")
        ("column_size", bpo::value<unsigned>()->default_value(64), "size in bytes for each column")
        ("sstables", bpo::value<unsigned>()->default_value(1), "number of sstables (valid only for compaction mode)")
        ("mode", bpo::value<sstring>()->default_value("index_write"), "one of: sequential_read, index_read, write, compaction, index_write (default)")
        ("testdir", bpo::value<sstring>()->default_value("/var/lib/scylla/perf-tests"), "directory in which to store the sstables");

    return app.run_deprecated(argc, argv, [&app] {
        auto test = make_lw_shared<distributed<test_env>>();

        auto cfg = test_env::conf();
        iterations = app.configuration()["iterations"].as<unsigned>();
        parallelism = app.configuration()["parallelism"].as<unsigned>();
        cfg.partitions = app.configuration()["partitions"].as<unsigned>();
        cfg.key_size = app.configuration()["key_size"].as<unsigned>();
        cfg.buffer_size = app.configuration()["buffer_size"].as<unsigned>() << 10;
        cfg.sstables = app.configuration()["sstables"].as<unsigned>();
        sstring dir = app.configuration()["testdir"].as<sstring>();
        cfg.dir = dir;
        auto mode = test_mode[app.configuration()["mode"].as<sstring>()];
        if ((mode == test_modes::index_read) || (mode == test_modes::index_write)) {
            cfg.num_columns = 0;
            cfg.column_size = 0;
        } else {
            cfg.num_columns = app.configuration()["num_columns"].as<unsigned>();
            cfg.column_size = app.configuration()["column_size"].as<unsigned>();
        }
        return test->start(std::move(cfg)).then([mode, dir, test] {
            engine().at_exit([test] { return test->stop(); });
            if ((mode == test_modes::index_read) ||
               (mode == test_modes::sequential_read)) {
                return test->invoke_on_all([] (test_env &t) {
                    return t.load_sstables(iterations);
                }).then_wrapped([] (future<> f) {
                    try {
                        f.get();
                    } catch (...) {
                        std::cerr << "An error occurred when trying to load test sstables. Did you run write mode yet?" << std::endl;
                        throw;
                    }
                });
            } else if ((mode == test_modes::index_write) || (mode == test_modes::write) || (mode == test_modes::compaction)) {
                return test_setup::create_empty_test_dir(dir);
            } else {
                throw std::invalid_argument("Invalid mode");
            }
        }).then([test, mode] {
            if (mode == test_modes::index_read) {
                return test_index_read(*test).then([test] {});
            } else if (mode == test_modes::sequential_read) {
                return test_sequential_read(*test).then([test] {});
            } else if ((mode == test_modes::index_write) || (mode == test_modes::write)) {
                return test_write(*test).then([test] {});
            } else if (mode == test_modes::compaction) {
                return test_compaction(*test).then([test] {});
            } else {
                throw std::invalid_argument("Invalid mode");
            }
        }).then([] {
            return engine().exit(0);
        }).or_terminate();
    });
}
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>

#include <flexcore/pure/event_sinks.hpp>
#include <flexcore/pure/event_sources.hpp>
#include <flexcore/core/connection.hpp>

using namespace fc;

namespace fc
{
namespace pure
{

template<class T>
struct event_sink_value
{
	void operator()(T in) { *storage = in; }
	std::shared_ptr<T> storage = std::make_shared<T>();
};

template<class T>
struct event_sink_vector
{
	void operator()(T in) {	storage->push_back(in);	}
	std::shared_ptr<std::vector<T>> storage = std::make_shared<std::vector<T>>();
};

} // namespace pure
} // namespace fc

BOOST_AUTO_TEST_SUITE(test_events)

BOOST_AUTO_TEST_CASE( connections )
{
	static_assert(is_active<pure::event_source<int>>{},
			"event_out_port is active by definition");
	static_assert(is_passive<pure::event_sink<int>>{},
			"event_in_port is passive by definition");
	static_assert(!is_active<pure::event_sink<int>>{},
			"event_in_port is not active by definition");
	static_assert(!is_passive<pure::event_source<int>>{},
			"event_out_port is not passive by definition");

	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler;

	connect(test_event, test_handler);
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 1);

	auto tmp_connection = test_event >> [](int i){return ++i;};
	static_assert(is_instantiation_of<
			detail::active_connection_proxy, decltype(tmp_connection)>{},
			"active port connected with standard connectable gets proxy");
	std::move(tmp_connection) >> test_handler;

	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 2);

	auto incr = [](int i){return ++i;};
	test_event >> incr >> incr >> incr >> test_handler;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(*(test_handler.storage), 4);
}

BOOST_AUTO_TEST_CASE( merge_events )
{
	pure::event_source<int> test_event;
	pure::event_source<int> test_event_2;
	pure::event_sink_vector<int> test_handler;

	test_event >> test_handler;
	test_event_2 >> test_handler;

	test_event.fire(0);
	BOOST_CHECK_EQUAL(test_handler.storage->size(), 1);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 0);

	test_event_2.fire(1);

	BOOST_CHECK_EQUAL(test_handler.storage->size(), 2);
	BOOST_CHECK_EQUAL(test_handler.storage->front(), 0);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 1);

}

BOOST_AUTO_TEST_CASE( split_events )
{
	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler_1;
	pure::event_sink_value<int> test_handler_2;

	test_event >> test_handler_1;
	test_event >> test_handler_2;

	test_event.fire(2);
	BOOST_CHECK_EQUAL(*(test_handler_1.storage), 2);
	BOOST_CHECK_EQUAL(*(test_handler_2.storage), 2);
}

BOOST_AUTO_TEST_CASE( in_port )
{
	int test_value = 0;

	auto test_writer = [&](int i) {test_value = i;};

	pure::event_sink<int> in_port(test_writer);
	pure::event_source<int> test_event;

	test_event >> in_port;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(test_value, 1);

	//test void event
	auto write_999 = [&]() {test_value = 999;};

	pure::event_sink<void> void_in(write_999);
	pure::event_source<void> void_out;
	void_out >> void_in;
	void_out.fire();
	BOOST_CHECK_EQUAL(test_value, 999);
}

BOOST_AUTO_TEST_CASE( lambda )
{
	int test_value = 0;

	auto write_666 = [&]() {test_value = 666;};
	pure::event_source<void> void_out_2;
	void_out_2 >> write_666;
	void_out_2.fire();
	BOOST_CHECK_EQUAL(test_value, 666);
}

namespace
{
template<class T>
void test_connection(const T& connection)
{
	int storage = 0;
	pure::event_source<int> a;
	pure::event_sink<int> d{[](int in){ BOOST_CHECK_EQUAL(in, 3);}};
	auto c = [&](int i) { storage = i; return i; };
	auto b = [](int i) { return i + 1; };

	connection(a,b,c,d);

	a.fire(2);
	BOOST_CHECK_EQUAL(storage, 3);
}
}

/**
 * Confirm that connecting ports and connectables
 * does not depend on any particular order.
 */
BOOST_AUTO_TEST_CASE( associativity )
{
	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> b >> c >> d;
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> b) >> (c >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> ((b >> c) >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> (b >> c)) >> d;
	});
}

namespace
{
template<class operation>
struct sink_t
{
	typedef void result_t;
	template <class T>
	void operator()(T&& in) { op(std::forward<T>(in)); }

	operation op;
};

template<class operation>
auto sink(const operation& op )
{
	return sink_t<operation>{op};
}
}

BOOST_AUTO_TEST_CASE( test_polymorphic_lambda )
{
	int test_value = 0;

	pure::event_source<int> p;
	auto write = sink([&](auto in) {test_value = in;});

	static_assert(is_passive_sink<decltype(write)>{}, "");

	p >> write;
	BOOST_CHECK_EQUAL(test_value, 0);
	p.fire(4);
	BOOST_CHECK_EQUAL(test_value, 4);
}

BOOST_AUTO_TEST_CASE(test_sink_has_callback)
{
	static_assert(has_register_function<pure::event_sink<void>>(0),
				"type is defined with ability to register a callback");
}

template <class T>
struct disconnecting_event_sink : public pure::event_sink<T>
{
	disconnecting_event_sink() :
		pure::event_sink<T>(
			[&](T in){
				*storage = in;
			}
		)
	{
	}

	std::shared_ptr<T> storage = std::make_shared<T>();
};

BOOST_AUTO_TEST_CASE(test_sink_deleted_callback)
{
	disconnecting_event_sink<int> test_sink1;

	{
		pure::event_source<int> test_source;

		disconnecting_event_sink<int> test_sink4;
		test_source >> test_sink1;
		test_source.fire(5);
		BOOST_CHECK_EQUAL(*(test_sink1.storage), 5);

		{
			disconnecting_event_sink<int> test_sink2;
			disconnecting_event_sink<int> test_sink3;
			test_source >> test_sink2;
			test_source >> test_sink3;
			test_source.fire(6);
			BOOST_CHECK_EQUAL(*(test_sink2.storage), 6);
			BOOST_CHECK_EQUAL(*(test_sink3.storage), 6);

			test_source >> test_sink4;
			test_source.fire(7);
			BOOST_CHECK_EQUAL(*(test_sink4.storage), 7);

			BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 4);
		}

		BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);

		// this primarily checks, that no exception is thrown
		// since the connections from test_source to sink1-3 are deleted.
		test_source.fire(8);
		BOOST_CHECK_EQUAL(*(test_sink4.storage), 8);
	}

}

BOOST_AUTO_TEST_CASE(test_delete_with_lambda_in_connection)
{
	disconnecting_event_sink<int> test_sink;

	pure::event_source<int> test_source;

	(test_source >> [](int i){ return i+1; }) >> test_sink;

	{
		disconnecting_event_sink<int> test_sink_2;
		test_source >> ([](int i){ return i+1; }
				>> [](int i){ return i+1; })
				>> test_sink_2;
				test_source.fire(10);
				BOOST_CHECK_EQUAL(*(test_sink_2.storage), 12);
				BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);
	}

	BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 1);

	test_source.fire(11);
	BOOST_CHECK_EQUAL(*(test_sink.storage), 12);
}

BOOST_AUTO_TEST_CASE(test_connect_after_move_of_active)
{
	pure::event_source<int> p;
	pure::event_source<int> p2 = std::move(p);
	bool fired = false;
	pure::event_sink<int> sink([&](int v) { fired = true; BOOST_CHECK_EQUAL(v, 99); });
	p2 >> sink;
	p2.fire(99);
	BOOST_CHECK(fired);
}

BOOST_AUTO_TEST_CASE(test_connect_after_move_of_passive)
{
	pure::event_source<int> src;
	int sink_val = 0;
	int ctr = 0;
	pure::event_sink<int> sink1{[](int){}};
	{
		pure::event_sink<int> sink2{[&](int v) { ++ctr; sink_val = v; }};
		sink1 = std::move(sink2);
		src >> sink1;
		src >> sink2;
		// after the block ends sink2 should be disconnected
	}
	src.fire(99);
	BOOST_CHECK_EQUAL(sink_val, 99);
	BOOST_CHECK_EQUAL(ctr, 1);
}

BOOST_AUTO_TEST_CASE(test_move_active_after_connect)
{
	pure::event_source<int> p;
	bool fired = false;
	pure::event_sink<int> sink([&](int v) { fired = true; BOOST_CHECK_EQUAL(v, 99); });
	p >> sink;
	pure::event_source<int> p2 = std::move(p);
	p2.fire(99);
	BOOST_CHECK(fired);
}

BOOST_AUTO_TEST_CASE(lambda_as_sink)
{
	pure::event_source<int> src;
	int called = 0;
	auto lambda = [&](auto v) {
		BOOST_CHECK_EQUAL(v, 99); called++;
	};
	auto mid = [&](auto v) {
		BOOST_CHECK_EQUAL(v, 99);
		called++;
		return v;
	};
	src >> mid >> mid >> std::move(lambda);
	src.fire(99);
	BOOST_CHECK_EQUAL(called, 3);
	bool is_passive_sink_for = fc::is_passive_sink_for<decltype(lambda), int>{};
	BOOST_CHECK(is_passive_sink_for);
}

namespace
{
struct strongly_typed
{
	explicit strongly_typed(double) {}
};
}

BOOST_AUTO_TEST_CASE( type_changing_lambdas )
{
	pure::event_source<double> src;
	bool called_1 = false;
	bool called_2 = false;
	src >> [&](double d) {
		called_1 = true;
		return strongly_typed{d};
	} >> [&](strongly_typed) {
		called_2 = true;
	};
	src.fire(1.0);
	BOOST_CHECK(called_1);
	BOOST_CHECK(called_2);
}

BOOST_AUTO_TEST_CASE( type_changing_lambda_with_void )
{
	pure::event_source<void> src;
	bool called_1 = false;
	bool called_2 = false;
	src >> [&]() {
		called_1 = true;
		return strongly_typed{1.0};
	} >> [&](strongly_typed) {
		called_2 = true;
	};
	src.fire();
	BOOST_CHECK(called_1);
	BOOST_CHECK(called_2);
}

BOOST_AUTO_TEST_CASE( type_changing_lambda_without_void )
{
	pure::event_source<double> src;
	bool called_1 = false;
	bool called_2 = false;
	src >> [&](double d) {
		called_1 = true;
		return strongly_typed{d};
	} >> [&](strongly_typed) {
		called_2 = true;
	};
	src.fire(1.0);
	BOOST_CHECK(called_1);
	BOOST_CHECK(called_2);
}
BOOST_AUTO_TEST_SUITE_END()
<commit_msg>removed bad event_tests<commit_after>#include <boost/test/unit_test.hpp>

#include <flexcore/pure/event_sinks.hpp>
#include <flexcore/pure/event_sources.hpp>
#include <flexcore/core/connection.hpp>

#include <tests/pure/sink_fixture.hpp>

using namespace fc;

namespace fc
{
namespace pure
{

template<class T>
struct event_sink_value
{
	void operator()(T in) { *storage = in; }
	std::shared_ptr<T> storage = std::make_shared<T>();
};

template<class T>
struct event_sink_vector
{
	void operator()(T in) {	storage->push_back(in);	}
	std::shared_ptr<std::vector<T>> storage = std::make_shared<std::vector<T>>();
};

} // namespace pure
} // namespace fc

BOOST_AUTO_TEST_SUITE(test_events)

BOOST_AUTO_TEST_CASE( merge_events )
{
	pure::event_source<int> test_event;
	pure::event_source<int> test_event_2;
	pure::event_sink_vector<int> test_handler;

	test_event >> test_handler;
	test_event_2 >> test_handler;

	test_event.fire(0);
	BOOST_CHECK_EQUAL(test_handler.storage->size(), 1);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 0);

	test_event_2.fire(1);

	BOOST_CHECK_EQUAL(test_handler.storage->size(), 2);
	BOOST_CHECK_EQUAL(test_handler.storage->front(), 0);
	BOOST_CHECK_EQUAL(test_handler.storage->back(), 1);

}

BOOST_AUTO_TEST_CASE( split_events )
{
	pure::event_source<int> test_event;
	pure::event_sink_value<int> test_handler_1;
	pure::event_sink_value<int> test_handler_2;

	test_event >> test_handler_1;
	test_event >> test_handler_2;

	test_event.fire(2);
	BOOST_CHECK_EQUAL(*(test_handler_1.storage), 2);
	BOOST_CHECK_EQUAL(*(test_handler_2.storage), 2);
}

BOOST_AUTO_TEST_CASE( in_port )
{
	int test_value = 0;

	auto test_writer = [&](int i) {test_value = i;};

	pure::event_sink<int> in_port(test_writer);
	pure::event_source<int> test_event;

	test_event >> in_port;
	test_event.fire(1);
	BOOST_CHECK_EQUAL(test_value, 1);

	//test void event
	auto write_999 = [&]() {test_value = 999;};

	pure::event_sink<void> void_in(write_999);
	pure::event_source<void> void_out;
	void_out >> void_in;
	void_out.fire();
	BOOST_CHECK_EQUAL(test_value, 999);
}

BOOST_AUTO_TEST_CASE( lambda )
{
	int test_value = 0;

	auto write_666 = [&]() {test_value = 666;};
	pure::event_source<void> void_out_2;
	void_out_2 >> write_666;
	void_out_2.fire();
	BOOST_CHECK_EQUAL(test_value, 666);
}

namespace
{
template<class T>
void test_connection(const T& connection)
{
	int storage = 0;
	pure::event_source<int> a;
	pure::event_sink<int> d{[](int in){ BOOST_CHECK_EQUAL(in, 3);}};
	auto c = [&](int i) { storage = i; return i; };
	auto b = [](int i) { return i + 1; };

	connection(a,b,c,d);

	a.fire(2);
	BOOST_CHECK_EQUAL(storage, 3);
}
}

/**
 * Confirm that connecting ports and connectables
 * does not depend on any particular order.
 */
BOOST_AUTO_TEST_CASE( associativity )
{
	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> b >> c >> d;
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> b) >> (c >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		a >> ((b >> c) >> d);
	});

	test_connection([](auto& a, auto& b, auto& c, auto& d)
	{
		(a >> (b >> c)) >> d;
	});
}

namespace
{
template<class operation>
struct sink_t
{
	typedef void result_t;
	template <class T>
	void operator()(T&& in) { op(std::forward<T>(in)); }

	operation op;
};

template<class operation>
auto sink(const operation& op )
{
	return sink_t<operation>{op};
}
}

BOOST_AUTO_TEST_CASE( test_polymorphic_lambda )
{
	int test_value = 0;

	pure::event_source<int> p;
	auto write = sink([&](auto in) {test_value = in;});

	static_assert(is_passive_sink<decltype(write)>{}, "");

	p >> write;
	BOOST_CHECK_EQUAL(test_value, 0);
	p.fire(4);
	BOOST_CHECK_EQUAL(test_value, 4);
}

BOOST_AUTO_TEST_CASE(test_sink_has_callback)
{
	static_assert(has_register_function<pure::event_sink<void>>(0),
				"type is defined with ability to register a callback");
}

template <class T>
struct disconnecting_event_sink : public pure::event_sink<T>
{
	disconnecting_event_sink() :
		pure::event_sink<T>(
			[&](T in){
				*storage = in;
			}
		)
	{
	}

	std::shared_ptr<T> storage = std::make_shared<T>();
};

BOOST_AUTO_TEST_CASE(test_sink_deleted_callback)
{
	disconnecting_event_sink<int> test_sink1;

	{
		pure::event_source<int> test_source;

		disconnecting_event_sink<int> test_sink4;
		test_source >> test_sink1;
		test_source.fire(5);
		BOOST_CHECK_EQUAL(*(test_sink1.storage), 5);

		{
			disconnecting_event_sink<int> test_sink2;
			disconnecting_event_sink<int> test_sink3;
			test_source >> test_sink2;
			test_source >> test_sink3;
			test_source.fire(6);
			BOOST_CHECK_EQUAL(*(test_sink2.storage), 6);
			BOOST_CHECK_EQUAL(*(test_sink3.storage), 6);

			test_source >> test_sink4;
			test_source.fire(7);
			BOOST_CHECK_EQUAL(*(test_sink4.storage), 7);

			BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 4);
		}

		BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);

		// this primarily checks, that no exception is thrown
		// since the connections from test_source to sink1-3 are deleted.
		test_source.fire(8);
		BOOST_CHECK_EQUAL(*(test_sink4.storage), 8);
	}

}

BOOST_AUTO_TEST_CASE(test_delete_with_lambda_in_connection)
{
	disconnecting_event_sink<int> test_sink;

	pure::event_source<int> test_source;

	(test_source >> [](int i){ return i+1; }) >> test_sink;

	{
		disconnecting_event_sink<int> test_sink_2;
		test_source >> ([](int i){ return i+1; }
				>> [](int i){ return i+1; })
				>> test_sink_2;
				test_source.fire(10);
				BOOST_CHECK_EQUAL(*(test_sink_2.storage), 12);
				BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 2);
	}

	BOOST_CHECK_EQUAL(test_source.nr_connected_handlers(), 1);

	test_source.fire(11);
	BOOST_CHECK_EQUAL(*(test_sink.storage), 12);
}

BOOST_AUTO_TEST_CASE(test_connect_after_move_of_active)
{
	pure::event_source<int> p;
	pure::event_source<int> p2 = std::move(p);
	bool fired = false;
	pure::event_sink<int> sink([&](int v) { fired = true; BOOST_CHECK_EQUAL(v, 99); });
	p2 >> sink;
	p2.fire(99);
	BOOST_CHECK(fired);
}

BOOST_AUTO_TEST_CASE(test_connect_after_move_of_passive)
{
	pure::event_source<int> src;
	int sink_val = 0;
	int ctr = 0;
	pure::event_sink<int> sink1{[](int){}};
	{
		pure::event_sink<int> sink2{[&](int v) { ++ctr; sink_val = v; }};
		sink1 = std::move(sink2);
		src >> sink1;
		src >> sink2;
		// after the block ends sink2 should be disconnected
	}
	src.fire(99);
	BOOST_CHECK_EQUAL(sink_val, 99);
	BOOST_CHECK_EQUAL(ctr, 1);
}

BOOST_AUTO_TEST_CASE(test_move_active_after_connect)
{
	pure::event_source<int> p;
	bool fired = false;
	pure::event_sink<int> sink([&](int v) { fired = true; BOOST_CHECK_EQUAL(v, 99); });
	p >> sink;
	pure::event_source<int> p2 = std::move(p);
	p2.fire(99);
	BOOST_CHECK(fired);
}

BOOST_AUTO_TEST_CASE(lambda_as_sink)
{
	pure::event_source<int> src;
	int called = 0;
	auto lambda = [&](auto v) {
		BOOST_CHECK_EQUAL(v, 99); called++;
	};
	auto mid = [&](auto v) {
		BOOST_CHECK_EQUAL(v, 99);
		called++;
		return v;
	};
	src >> mid >> mid >> std::move(lambda);
	src.fire(99);
	BOOST_CHECK_EQUAL(called, 3);
	bool is_passive_sink_for = fc::is_passive_sink_for<decltype(lambda), int>{};
	BOOST_CHECK(is_passive_sink_for);
}

namespace
{
struct strongly_typed
{
	explicit strongly_typed(double) {}
};
}

BOOST_AUTO_TEST_CASE( type_changing_lambdas )
{
	pure::event_source<double> src;
	bool called_1 = false;
	bool called_2 = false;
	src >> [&](double d) {
		called_1 = true;
		return strongly_typed{d};
	} >> [&](strongly_typed) {
		called_2 = true;
	};
	src.fire(1.0);
	BOOST_CHECK(called_1);
	BOOST_CHECK(called_2);
}

BOOST_AUTO_TEST_CASE( type_changing_lambda_with_void )
{
	pure::event_source<void> src;
	bool called_1 = false;
	bool called_2 = false;
	src >> [&]() {
		called_1 = true;
		return strongly_typed{1.0};
	} >> [&](strongly_typed) {
		called_2 = true;
	};
	src.fire();
	BOOST_CHECK(called_1);
	BOOST_CHECK(called_2);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "TiglViewerConsole.h"

Console::Console(QWidget *parent) :
    QPlainTextEdit(parent)
{
    prompt = "TiglViewer> ";

    QPalette p = palette();
    p.setColor(QPalette::Base, Qt::black);
    p.setColor(QPalette::Text, Qt::green);
    setPalette(p);

    history = new QStringList;
    historyPos = 0;
    insertPrompt(false);
    isLocked = false;
}

void Console::keyPressEvent(QKeyEvent *event)
{
    if(isLocked)
    return;
    if(event->key() >= 0x20 && event->key() <= 0x7e
       && (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::ShiftModifier))
    QPlainTextEdit::keyPressEvent(event);
    if(event->key() == Qt::Key_Backspace
       && event->modifiers() == Qt::NoModifier
       && textCursor().positionInBlock() > prompt.length())
    QPlainTextEdit::keyPressEvent(event);
    if(event->key() == Qt::Key_Return && event->modifiers() == Qt::NoModifier)
    onEnter();
    if(event->key() == Qt::Key_Up && event->modifiers() == Qt::NoModifier)
    historyBack();
    if(event->key() == Qt::Key_Down && event->modifiers() == Qt::NoModifier)
    historyForward();
    QString cmd = textCursor().block().text().mid(prompt.length());
    emit onChange(cmd);
}

void Console::mousePressEvent(QMouseEvent *)
{
    setFocus();
}

void Console::mouseDoubleClickEvent(QMouseEvent *){}

void Console::contextMenuEvent(QContextMenuEvent *){}

void Console::onEnter()
{
    if(textCursor().positionInBlock() == prompt.length())
    {
    insertPrompt();
    return;
    }
    QString cmd = textCursor().block().text().mid(prompt.length());
    isLocked = true;
    historyAdd(cmd);
    emit onCommand(cmd);
}

void Console::output(QString s)
{
    appendHtml(QString("%1

").arg(s));
    insertPrompt();
    isLocked = false;
}

void Console::insertPrompt(bool insertNewBlock)
{
    if(insertNewBlock)
    textCursor().insertBlock();
    QTextCharFormat format;
    format.setForeground(Qt::green);
    textCursor().setBlockCharFormat(format);
    textCursor().insertText(prompt);
    scrollDown();
}

void Console::scrollDown()
{
    QScrollBar *vbar = verticalScrollBar();
    vbar->setValue(vbar->maximum());
}

void Console::historyAdd(QString cmd)
{
    history->append(cmd);
    historyPos = history->length();
}

void Console::historyBack()
{
    if(!historyPos)
    return;
    QTextCursor cursor = textCursor();
    cursor.movePosition(QTextCursor::StartOfBlock);
    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    cursor.removeSelectedText();
    cursor.insertText(prompt + history->at(historyPos-1));
    setTextCursor(cursor);
    historyPos--;
}

void Console::historyForward()
{
    if(historyPos == history->length())
    return;
    QTextCursor cursor = textCursor();
    cursor.movePosition(QTextCursor::StartOfBlock);
    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    cursor.removeSelectedText();
    if(historyPos == history->length() - 1)
    cursor.insertText(prompt);
    else
    cursor.insertText(prompt + history->at(historyPos + 1));
    setTextCursor(cursor);
    historyPos++;
}
<commit_msg>Changed code to compile with QT Version < 4.7<commit_after>#include "TiglViewerConsole.h"

Console::Console(QWidget *parent) :
    QPlainTextEdit(parent)
{
    prompt = "TiglViewer> ";

    QPalette p = palette();
    p.setColor(QPalette::Base, Qt::black);
    p.setColor(QPalette::Text, Qt::green);
    setPalette(p);

    history = new QStringList;
    historyPos = 0;
    insertPrompt(false);
    isLocked = false;
}

void Console::keyPressEvent(QKeyEvent *event)
{
    if(isLocked)
        return;

    if(event->key() >= 0x20 && event->key() <= 0x7e &&
       (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::ShiftModifier))
        QPlainTextEdit::keyPressEvent(event);

    if(event->key() == Qt::Key_Backspace &&
       event->modifiers() == Qt::NoModifier &&
       textCursor().position() - textCursor().block().position() > prompt.length())
        QPlainTextEdit::keyPressEvent(event);

    if(event->key() == Qt::Key_Return && event->modifiers() == Qt::NoModifier)
        onEnter();

    if(event->key() == Qt::Key_Up && event->modifiers() == Qt::NoModifier)
        historyBack();

    if(event->key() == Qt::Key_Down && event->modifiers() == Qt::NoModifier)
        historyForward();

    QString cmd = textCursor().block().text().mid(prompt.length());
    emit onChange(cmd);
}

void Console::mousePressEvent(QMouseEvent *)
{
    setFocus();
}

void Console::mouseDoubleClickEvent(QMouseEvent *){}

void Console::contextMenuEvent(QContextMenuEvent *){}

void Console::onEnter()
{
    if(textCursor().position() - textCursor().block().position() == prompt.length()){
        insertPrompt();
        return;
    }

    QString cmd = textCursor().block().text().mid(prompt.length());
    isLocked = true;
    historyAdd(cmd);
    emit onCommand(cmd);
}

void Console::output(QString s)
{
    appendHtml(QString("%1

").arg(s));
    insertPrompt();
    isLocked = false;
}

void Console::insertPrompt(bool insertNewBlock)
{
    if(insertNewBlock)
    textCursor().insertBlock();
    QTextCharFormat format;
    format.setForeground(Qt::green);
    textCursor().setBlockCharFormat(format);
    textCursor().insertText(prompt);
    scrollDown();
}

void Console::scrollDown()
{
    QScrollBar *vbar = verticalScrollBar();
    vbar->setValue(vbar->maximum());
}

void Console::historyAdd(QString cmd)
{
    history->append(cmd);
    historyPos = history->length();
}

void Console::historyBack()
{
    if(!historyPos)
    return;
    QTextCursor cursor = textCursor();
    cursor.movePosition(QTextCursor::StartOfBlock);
    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    cursor.removeSelectedText();
    cursor.insertText(prompt + history->at(historyPos-1));
    setTextCursor(cursor);
    historyPos--;
}

void Console::historyForward()
{
    if(historyPos == history->length())
    return;
    QTextCursor cursor = textCursor();
    cursor.movePosition(QTextCursor::StartOfBlock);
    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    cursor.removeSelectedText();
    if(historyPos == history->length() - 1)
    cursor.insertText(prompt);
    else
    cursor.insertText(prompt + history->at(historyPos + 1));
    setTextCursor(cursor);
    historyPos++;
}
<|endoftext|>


<commit_before>//
// Name: VehicleDlg.cpp
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#include <wx/colordlg.h>

#include "vtlib/vtlib.h"
#include "vtlib/core/TerrainScene.h"	// for vtGetContent
#include "vtui/Helper.h"				// for FillWithColor

#include "VehicleDlg.h"
#include "EnviroGUI.h"		// for g_App

extern void EnableContinuousRendering(bool bTrue);

// WDR: class implementations

//----------------------------------------------------------------------------
// VehicleDlg
//----------------------------------------------------------------------------

// WDR: event table for VehicleDlg

BEGIN_EVENT_TABLE(VehicleDlg,wxDialog)
	EVT_INIT_DIALOG (VehicleDlg::OnInitDialog)
	EVT_BUTTON( ID_SET_VEHICLE_COLOR, VehicleDlg::OnSetColor )
	EVT_CHOICE( ID_CHOICE_VEHICLES, VehicleDlg::OnChoiceVehicle )
END_EVENT_TABLE()

VehicleDlg::VehicleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	wxDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function VehicleDialogFunc for VehicleDlg
	VehicleDialogFunc( this, TRUE );

	m_options.m_Color.Set(255, 255, 0);
	wxColour rgb(255, 255, 0);
	m_ColorData.SetChooseFull(true);
	m_ColorData.SetColour(rgb);
}

void VehicleDlg::UpdateEnabling()
{
	vtContentManager3d &con = vtGetContent();

	GetSetColor()->Enable(false);
	vtItem *item = con.FindItemByName(m_options.m_Itemname);
	if (item)
	{
		if (item->GetValueBool("colorable"))
			GetSetColor()->Enable(true);
	}
}

void VehicleDlg::ItemChanged()
{
	m_options.m_Itemname = (const char *) GetChoice()->GetStringSelection().mb_str(wxConvUTF8);
	g_App.SetVehicleOptions(m_options);
}

void VehicleDlg::UpdateColorControl()
{
	// Case of a single edge, very simple.
	FillWithColor(GetColor(), m_options.m_Color);
}

// WDR: handler implementations for VehicleDlg

void VehicleDlg::OnChoiceVehicle( wxCommandEvent &event )
{
	ItemChanged();
	UpdateEnabling();
}

void VehicleDlg::OnSetColor( wxCommandEvent &event )
{
	EnableContinuousRendering(false);

	wxColourDialog dlg(this, &m_ColorData);
	if (dlg.ShowModal() == wxID_OK)
	{
		// Get the color from the dialog
		m_ColorData = dlg.GetColourData();
		wxColour rgb = m_ColorData.GetColour();
		m_options.m_Color.Set(rgb.Red(), rgb.Green(), rgb.Blue());

		UpdateColorControl();
		g_App.SetVehicleOptions(m_options);
	}
	EnableContinuousRendering(true);
}

void VehicleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	GetChoice()->Clear();

	// Refresh vehicle list
	wxString prev = GetChoice()->GetStringSelection();
	wxArrayString names;
	vtContentManager3d &con = vtGetContent();
	for (unsigned int i = 0; i < con.NumItems(); i++)
	{
		vtItem *item = con.GetItem(i);
		if (vtString("ground vehicle") == item->GetValueString("type") &&
			4 == item->GetValueInt("num_wheels"))
		{
			GetChoice()->Append(wxString(item->m_name, wxConvUTF8));
		}
	}
	if (prev != _T(""))
		GetChoice()->SetStringSelection(prev);
	else
		GetChoice()->SetSelection(0);

	ItemChanged();
	UpdateColorControl();
	UpdateEnabling();

	wxWindow::OnInitDialog(event);
}

<commit_msg>added non-pre-comp wx header<commit_after>//
// Name: VehicleDlg.cpp
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/colordlg.h>

#include "vtlib/vtlib.h"
#include "vtlib/core/TerrainScene.h"	// for vtGetContent
#include "vtui/Helper.h"				// for FillWithColor

#include "VehicleDlg.h"
#include "EnviroGUI.h"		// for g_App

extern void EnableContinuousRendering(bool bTrue);

// WDR: class implementations

//----------------------------------------------------------------------------
// VehicleDlg
//----------------------------------------------------------------------------

// WDR: event table for VehicleDlg

BEGIN_EVENT_TABLE(VehicleDlg,wxDialog)
	EVT_INIT_DIALOG (VehicleDlg::OnInitDialog)
	EVT_BUTTON( ID_SET_VEHICLE_COLOR, VehicleDlg::OnSetColor )
	EVT_CHOICE( ID_CHOICE_VEHICLES, VehicleDlg::OnChoiceVehicle )
END_EVENT_TABLE()

VehicleDlg::VehicleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	wxDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function VehicleDialogFunc for VehicleDlg
	VehicleDialogFunc( this, TRUE );

	m_options.m_Color.Set(255, 255, 0);
	wxColour rgb(255, 255, 0);
	m_ColorData.SetChooseFull(true);
	m_ColorData.SetColour(rgb);
}

void VehicleDlg::UpdateEnabling()
{
	vtContentManager3d &con = vtGetContent();

	GetSetColor()->Enable(false);
	vtItem *item = con.FindItemByName(m_options.m_Itemname);
	if (item)
	{
		if (item->GetValueBool("colorable"))
			GetSetColor()->Enable(true);
	}
}

void VehicleDlg::ItemChanged()
{
	m_options.m_Itemname = (const char *) GetChoice()->GetStringSelection().mb_str(wxConvUTF8);
	g_App.SetVehicleOptions(m_options);
}

void VehicleDlg::UpdateColorControl()
{
	// Case of a single edge, very simple.
	FillWithColor(GetColor(), m_options.m_Color);
}

// WDR: handler implementations for VehicleDlg

void VehicleDlg::OnChoiceVehicle( wxCommandEvent &event )
{
	ItemChanged();
	UpdateEnabling();
}

void VehicleDlg::OnSetColor( wxCommandEvent &event )
{
	EnableContinuousRendering(false);

	wxColourDialog dlg(this, &m_ColorData);
	if (dlg.ShowModal() == wxID_OK)
	{
		// Get the color from the dialog
		m_ColorData = dlg.GetColourData();
		wxColour rgb = m_ColorData.GetColour();
		m_options.m_Color.Set(rgb.Red(), rgb.Green(), rgb.Blue());

		UpdateColorControl();
		g_App.SetVehicleOptions(m_options);
	}
	EnableContinuousRendering(true);
}

void VehicleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	GetChoice()->Clear();

	// Refresh vehicle list
	wxString prev = GetChoice()->GetStringSelection();
	wxArrayString names;
	vtContentManager3d &con = vtGetContent();
	for (unsigned int i = 0; i < con.NumItems(); i++)
	{
		vtItem *item = con.GetItem(i);
		if (vtString("ground vehicle") == item->GetValueString("type") &&
			4 == item->GetValueInt("num_wheels"))
		{
			GetChoice()->Append(wxString(item->m_name, wxConvUTF8));
		}
	}
	if (prev != _T(""))
		GetChoice()->SetStringSelection(prev);
	else
		GetChoice()->SetSelection(0);

	ItemChanged();
	UpdateColorControl();
	UpdateEnabling();

	wxWindow::OnInitDialog(event);
}

<|endoftext|>


<commit_before>//
// Name: VehicleDlg.cpp
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/colordlg.h>

#include "vtlib/vtlib.h"
#include "vtlib/core/TerrainScene.h"	// for vtGetContent
#include "vtui/Helper.h"				// for FillWithColor

#include "VehicleDlg.h"
#include "EnviroGUI.h"		// for g_App

extern void EnableContinuousRendering(bool bTrue);

// WDR: class implementations

//----------------------------------------------------------------------------
// VehicleDlg
//----------------------------------------------------------------------------

// WDR: event table for VehicleDlg

BEGIN_EVENT_TABLE(VehicleDlg,wxDialog)
	EVT_INIT_DIALOG (VehicleDlg::OnInitDialog)
	EVT_BUTTON( ID_SET_VEHICLE_COLOR, VehicleDlg::OnSetColor )
	EVT_CHOICE( ID_CHOICE_VEHICLES, VehicleDlg::OnChoiceVehicle )
END_EVENT_TABLE()

VehicleDlg::VehicleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	wxDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function VehicleDialogFunc for VehicleDlg
	VehicleDialogFunc( this, TRUE );

	m_options.m_Color.Set(255, 255, 0);
	wxColour rgb(255, 255, 0);
	m_ColorData.SetChooseFull(true);
	m_ColorData.SetColour(rgb);
}

void VehicleDlg::UpdateEnabling()
{
	vtContentManager3d &con = vtGetContent();

	GetSetColor()->Enable(false);
	vtItem *item = con.FindItemByName(m_options.m_Itemname);
	if (item)
	{
		if (item->GetValueBool("colorable"))
			GetSetColor()->Enable(true);
	}
}

void VehicleDlg::ItemChanged()
{
	m_options.m_Itemname = (const char *) GetChoice()->GetStringSelection().mb_str(wxConvUTF8);
	g_App.SetVehicleOptions(m_options);
}

void VehicleDlg::UpdateColorControl()
{
	// Case of a single edge, very simple.
	FillWithColor(GetColor(), m_options.m_Color);
}

// WDR: handler implementations for VehicleDlg

void VehicleDlg::OnChoiceVehicle( wxCommandEvent &event )
{
	ItemChanged();
	UpdateEnabling();
}

void VehicleDlg::OnSetColor( wxCommandEvent &event )
{
	EnableContinuousRendering(false);

	wxColourDialog dlg(this, &m_ColorData);
	if (dlg.ShowModal() == wxID_OK)
	{
		// Get the color from the dialog
		m_ColorData = dlg.GetColourData();
		wxColour rgb = m_ColorData.GetColour();
		m_options.m_Color.Set(rgb.Red(), rgb.Green(), rgb.Blue());

		UpdateColorControl();
		g_App.SetVehicleOptions(m_options);
	}
	EnableContinuousRendering(true);
}

void VehicleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	GetChoice()->Clear();

	// Refresh vehicle list
	wxString prev = GetChoice()->GetStringSelection();
	wxArrayString names;
	vtContentManager3d &con = vtGetContent();
	for (unsigned int i = 0; i < con.NumItems(); i++)
	{
		vtItem *item = con.GetItem(i);
		if (vtString("ground vehicle") == item->GetValueString("type") &&
			4 == item->GetValueInt("num_wheels"))
		{
			GetChoice()->Append(wxString(item->m_name, wxConvUTF8));
		}
	}
	if (prev != _T(""))
		GetChoice()->SetStringSelection(prev);
	else
		GetChoice()->SetSelection(0);

	ItemChanged();
	UpdateColorControl();
	UpdateEnabling();

	wxWindow::OnInitDialog(event);
}

<commit_msg>added safety check (RJ)<commit_after>//
// Name: VehicleDlg.cpp
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/colordlg.h>

#include "vtlib/vtlib.h"
#include "vtlib/core/TerrainScene.h"	// for vtGetContent
#include "vtui/Helper.h"				// for FillWithColor

#include "VehicleDlg.h"
#include "EnviroGUI.h"		// for g_App

extern void EnableContinuousRendering(bool bTrue);

// WDR: class implementations

//----------------------------------------------------------------------------
// VehicleDlg
//----------------------------------------------------------------------------

// WDR: event table for VehicleDlg

BEGIN_EVENT_TABLE(VehicleDlg,wxDialog)
	EVT_INIT_DIALOG (VehicleDlg::OnInitDialog)
	EVT_BUTTON( ID_SET_VEHICLE_COLOR, VehicleDlg::OnSetColor )
	EVT_CHOICE( ID_CHOICE_VEHICLES, VehicleDlg::OnChoiceVehicle )
END_EVENT_TABLE()

VehicleDlg::VehicleDlg( wxWindow *parent, wxWindowID id, const wxString &title,
	const wxPoint &position, const wxSize& size, long style ) :
	wxDialog( parent, id, title, position, size, style )
{
	// WDR: dialog function VehicleDialogFunc for VehicleDlg
	VehicleDialogFunc( this, TRUE );

	m_options.m_Color.Set(255, 255, 0);
	wxColour rgb(255, 255, 0);
	m_ColorData.SetChooseFull(true);
	m_ColorData.SetColour(rgb);
}

void VehicleDlg::UpdateEnabling()
{
	vtContentManager3d &con = vtGetContent();

	GetSetColor()->Enable(false);
	vtItem *item = con.FindItemByName(m_options.m_Itemname);
	if (item)
	{
		if (item->GetValueBool("colorable"))
			GetSetColor()->Enable(true);
	}
}

void VehicleDlg::ItemChanged()
{
	m_options.m_Itemname = (const char *) GetChoice()->GetStringSelection().mb_str(wxConvUTF8);
	g_App.SetVehicleOptions(m_options);
}

void VehicleDlg::UpdateColorControl()
{
	// Case of a single edge, very simple.
	FillWithColor(GetColor(), m_options.m_Color);
}

// WDR: handler implementations for VehicleDlg

void VehicleDlg::OnChoiceVehicle( wxCommandEvent &event )
{
	ItemChanged();
	UpdateEnabling();
}

void VehicleDlg::OnSetColor( wxCommandEvent &event )
{
	EnableContinuousRendering(false);

	wxColourDialog dlg(this, &m_ColorData);
	if (dlg.ShowModal() == wxID_OK)
	{
		// Get the color from the dialog
		m_ColorData = dlg.GetColourData();
		wxColour rgb = m_ColorData.GetColour();
		m_options.m_Color.Set(rgb.Red(), rgb.Green(), rgb.Blue());

		UpdateColorControl();
		g_App.SetVehicleOptions(m_options);
	}
	EnableContinuousRendering(true);
}

void VehicleDlg::OnInitDialog(wxInitDialogEvent& event)
{
	GetChoice()->Clear();

	// Refresh vehicle list
	wxString prev = GetChoice()->GetStringSelection();
	wxArrayString names;
	vtContentManager3d &con = vtGetContent();
	for (unsigned int i = 0; i < con.NumItems(); i++)
	{
		vtItem *item = con.GetItem(i);
		const char *type = item->GetValueString("type");
		int wheels = item->GetValueInt("num_wheels");
		if (type && vtString(type) == "ground vehicle" && wheels == 4)
		{
			GetChoice()->Append(wxString(item->m_name, wxConvUTF8));
		}
	}
	if (prev != _T(""))
		GetChoice()->SetStringSelection(prev);
	else
		GetChoice()->SetSelection(0);

	ItemChanged();
	UpdateColorControl();
	UpdateEnabling();

	wxWindow::OnInitDialog(event);
}

<|endoftext|>