<commit_before>/* Copyright 2022 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 "tensorflow/dtensor/mlir/sparse_expansions/dynamic_enqueue_sparse_expander.h"

#include "mlir/IR/BuiltinAttributes.h"  // from @llvm-project
#include "mlir/IR/Operation.h"  // from @llvm-project
#include "mlir/IR/OperationSupport.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/collection_ops_util.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/statusor.h"
#include "tensorflow/dtensor/mlir/sparse_expander_common.h"
#include "tensorflow/dtensor/mlir/value_utils.h"

namespace tensorflow {
namespace dtensor {

namespace {

// Indices tensor should be transformed from a shape [?, 2] tensor to a
// [?, 3] tensor padded with 0's because
// EnqueueTPUEmbeddingArbitraryTensorBatchOp expects a [?, 3] indices tensor.
StatusOr<mlir::Value> ExpandIndices(mlir::OpBuilder& builder,
                                    mlir::Value indices) {
  int64_t num_dim =
      indices.getType().dyn_cast<mlir::RankedTensorType>().getDimSize(1);
  if (num_dim != 2)
    return errors::Unimplemented(
        "Sparse tensors with dense rank not equal to 2 is not yet supported in "
        "DTensor.");
  mlir::Location loc = indices.getLoc();
  auto indices_padded_type = mlir::RankedTensorType::get(
      {-1, 3},
      indices.getType().dyn_cast<mlir::RankedTensorType>().getElementType());
  // Little trick to make a rank-2 tensor of [[0,0], [0,1]] using rank 1
  // constants.
  mlir::Value indices_padding = builder.create<mlir::TF::ReshapeOp>(
      loc,
      mlir::TF::collection_ops_util::GetR1Const({0, 0, 0, 1}, builder, loc),
      mlir::TF::collection_ops_util::GetR1Const({2, 2}, builder, loc));
  mlir::Value indices_padded =
      builder.create<mlir::TF::PadOp>(loc, indices_padded_type,
                                      /*input=*/indices,
                                      /*paddings=*/indices_padding);
  return indices_padded;
}

}  // namespace

StatusOr<mlir::Operation*> DynamicEnqueueSparseExpander::ExpandOp(
    mlir::Operation* op) {
  mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp dense_enqueue_op =
      mlir::cast<mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp>(
          op);

  mlir::OpBuilder builder(dense_enqueue_op);
  mlir::Location location = dense_enqueue_op->getLoc();

  mlir::OperandRange feature = dense_enqueue_op.getEmbeddingIndices();
  llvm::SmallVector<mlir::Value, 4> indices;
  llvm::SmallVector<mlir::Value, 4> values;

  for (mlir::Value sparse_feature_value : feature) {
    if (!IsSparseValue(sparse_feature_value)) {
      return errors::Internal(
          "Expected feature input to DynamicEnqueueOp to be a sparse input, "
          "but was not. This should not happen.");
    }
    // Indices tensor may need to be expanded to a different shape
    // for Enqueue op to work properly.
    TF_ASSIGN_OR_RETURN(
        mlir::Value expanded_indices,
        ExpandIndices(
            builder, GetIndicesFromSparseTensor(sparse_feature_value).value()));
    indices.push_back(expanded_indices);
    values.push_back(GetValuesFromSparseTensor(sparse_feature_value).value());
  }
  // Insert a new op with new sparse operands, and delete the old one.
  // This op does not have a return value so we do not need to replace any
  // consumers.
  mlir::Operation* sparse_enqueue_op =
      builder
          .create<mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp>(
              location,
              /*sample_indices_or_row_splits_list=*/indices,
              /*embedding_indices=*/values,
              /*aggregation_weights=*/dense_enqueue_op.getAggregationWeights(),
              /*mode_override=*/
              dense_enqueue_op.getModeOverride(),
              /*device_ordinal=*/dense_enqueue_op.getDeviceOrdinal(),
              /*combiners=*/dense_enqueue_op.getCombiners());
  dense_enqueue_op.erase();
  return sparse_enqueue_op;
}

}  // namespace dtensor
}  // namespace tensorflow
<commit_msg>[DTensor] Fix test broken by the MLIR kDynamic change<commit_after>/* Copyright 2022 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 "tensorflow/dtensor/mlir/sparse_expansions/dynamic_enqueue_sparse_expander.h"

#include "mlir/IR/BuiltinAttributes.h"  // from @llvm-project
#include "mlir/IR/Operation.h"  // from @llvm-project
#include "mlir/IR/OperationSupport.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/collection_ops_util.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/statusor.h"
#include "tensorflow/dtensor/mlir/sparse_expander_common.h"
#include "tensorflow/dtensor/mlir/value_utils.h"

namespace tensorflow {
namespace dtensor {

namespace {

// Indices tensor should be transformed from a shape [?, 2] tensor to a
// [?, 3] tensor padded with 0's because
// EnqueueTPUEmbeddingArbitraryTensorBatchOp expects a [?, 3] indices tensor.
StatusOr<mlir::Value> ExpandIndices(mlir::OpBuilder& builder,
                                    mlir::Value indices) {
  int64_t num_dim =
      indices.getType().dyn_cast<mlir::RankedTensorType>().getDimSize(1);
  if (num_dim != 2)
    return errors::Unimplemented(
        "Sparse tensors with dense rank not equal to 2 is not yet supported in "
        "DTensor.");
  mlir::Location loc = indices.getLoc();
  auto indices_padded_type = mlir::RankedTensorType::get(
      {mlir::ShapedType::kDynamic, 3},
      indices.getType().dyn_cast<mlir::RankedTensorType>().getElementType());
  // Little trick to make a rank-2 tensor of [[0,0], [0,1]] using rank 1
  // constants.
  mlir::Value indices_padding = builder.create<mlir::TF::ReshapeOp>(
      loc,
      mlir::TF::collection_ops_util::GetR1Const({0, 0, 0, 1}, builder, loc),
      mlir::TF::collection_ops_util::GetR1Const({2, 2}, builder, loc));
  mlir::Value indices_padded =
      builder.create<mlir::TF::PadOp>(loc, indices_padded_type,
                                      /*input=*/indices,
                                      /*paddings=*/indices_padding);
  return indices_padded;
}

}  // namespace

StatusOr<mlir::Operation*> DynamicEnqueueSparseExpander::ExpandOp(
    mlir::Operation* op) {
  mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp dense_enqueue_op =
      mlir::cast<mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp>(
          op);

  mlir::OpBuilder builder(dense_enqueue_op);
  mlir::Location location = dense_enqueue_op->getLoc();

  mlir::OperandRange feature = dense_enqueue_op.getEmbeddingIndices();
  llvm::SmallVector<mlir::Value, 4> indices;
  llvm::SmallVector<mlir::Value, 4> values;

  for (mlir::Value sparse_feature_value : feature) {
    if (!IsSparseValue(sparse_feature_value)) {
      return errors::Internal(
          "Expected feature input to DynamicEnqueueOp to be a sparse input, "
          "but was not. This should not happen.");
    }
    // Indices tensor may need to be expanded to a different shape
    // for Enqueue op to work properly.
    TF_ASSIGN_OR_RETURN(
        mlir::Value expanded_indices,
        ExpandIndices(
            builder, GetIndicesFromSparseTensor(sparse_feature_value).value()));
    indices.push_back(expanded_indices);
    values.push_back(GetValuesFromSparseTensor(sparse_feature_value).value());
  }
  // Insert a new op with new sparse operands, and delete the old one.
  // This op does not have a return value so we do not need to replace any
  // consumers.
  mlir::Operation* sparse_enqueue_op =
      builder
          .create<mlir::TF::DynamicEnqueueTPUEmbeddingArbitraryTensorBatchOp>(
              location,
              /*sample_indices_or_row_splits_list=*/indices,
              /*embedding_indices=*/values,
              /*aggregation_weights=*/dense_enqueue_op.getAggregationWeights(),
              /*mode_override=*/
              dense_enqueue_op.getModeOverride(),
              /*device_ordinal=*/dense_enqueue_op.getDeviceOrdinal(),
              /*combiners=*/dense_enqueue_op.getCombiners());
  dense_enqueue_op.erase();
  return sparse_enqueue_op;
}

}  // namespace dtensor
}  // namespace tensorflow
<|endoftext|>


<commit_before>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <fc/time.hpp>

#pragma GCC diagnostic ignored "-Wunused-variable"

namespace eosio { namespace chain { namespace config {

typedef __uint128_t uint128_t;

const static auto default_blocks_dir_name    = "blocks";
const static auto reversible_blocks_dir_name = "reversible";
const static auto default_reversible_cache_size = 340*1024*1024ll;/// 1MB * 340 blocks based on 21 producer BFT delay

const static auto default_state_dir_name     = "state";
const static auto forkdb_filename            = "forkdb.dat";
const static auto default_state_size            = 1*1024*1024*1024ll;

const static uint64_t system_account_name    = N(eosio);
const static uint64_t null_account_name      = N(eosio.null);
const static uint64_t producers_account_name = N(eosio.prods);

// Active permission of producers account requires greater than 2/3 of the producers to authorize
const static uint64_t majority_producers_permission_name = N(prod.major); // greater than 1/2 of producers needed to authorize
const static uint64_t minority_producers_permission_name = N(prod.minor); // greater than 1/3 of producers needed to authorize0

const static uint64_t eosio_auth_scope       = N(eosio.auth);
const static uint64_t eosio_all_scope        = N(eosio.all);

const static uint64_t active_name = N(active);
const static uint64_t owner_name  = N(owner);
const static uint64_t eosio_any_name = N(eosio.any);
const static uint64_t eosio_code_name = N(eosio.code);

const static int      block_interval_ms = 500;
const static int      block_interval_us = block_interval_ms*1000;
const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000.

/** Percentages are fixed point with a denominator of 10,000 */
const static int percent_100 = 10000;
const static int percent_1   = 100;

const static uint32_t  required_producer_participation = 33 * config::percent_1;

static const uint32_t account_cpu_usage_average_window_ms  = 24*60*60*1000l;
static const uint32_t account_net_usage_average_window_ms  = 24*60*60*1000l;
static const uint32_t block_cpu_usage_average_window_ms    = 60*1000l;
static const uint32_t block_size_average_window_ms         = 60*1000l;

//const static uint64_t   default_max_storage_size       = 10 * 1024;
//const static uint32_t   default_max_trx_runtime        = 10*1000;
//const static uint32_t   default_max_gen_trx_size       = 64 * 1024;

const static uint32_t   rate_limiting_precision        = 1000*1000;

const static uint32_t   default_max_block_net_usage                 = 1024 * 1024; /// at 500ms blocks and 200byte trx, this enables ~10,000 TPS burst
const static uint32_t   default_target_block_net_usage_pct           = 10 * percent_1; /// we target 1000 TPS
const static uint32_t   default_max_transaction_net_usage            = default_max_block_net_usage / 2;
const static uint32_t   default_base_per_transaction_net_usage       = 12;  // 12 bytes (11 bytes for worst case of transaction_receipt_header + 1 byte for static_variant tag)
const static uint32_t   default_net_usage_leeway                     = 500; // TODO: is this reasonable?
const static uint32_t   default_context_free_discount_net_usage_num  = 20; // TODO: is this reasonable?
const static uint32_t   default_context_free_discount_net_usage_den  = 100;
const static uint32_t   transaction_id_net_usage                     = 32; // 32 bytes for the size of a transaction id

const static uint32_t   default_max_block_cpu_usage                 = 200'000; /// max block cpu usage in microseconds
const static uint32_t   default_target_block_cpu_usage_pct          = percent_1; /// target 1000 TPS
const static uint32_t   default_max_transaction_cpu_usage           = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds
const static uint32_t   default_min_transaction_cpu_usage           = 100; /// min trx cpu usage in microseconds (10000 TPS equiv)

const static uint32_t   default_max_trx_lifetime               = 60*60; // 1 hour
const static uint32_t   default_deferred_trx_expiration_window = 10*60; // 10 minutes
const static uint32_t   default_max_trx_delay                  = 45*24*3600; // 45 days
const static uint32_t   default_max_inline_action_size         = 4 * 1024;   // 4 KB
const static uint16_t   default_max_inline_action_depth        = 4;
const static uint16_t   default_max_auth_depth                 = 6;

const static uint32_t   min_net_usage_delta_between_base_and_max_for_trx  = 10*1024;
// Should be large enough to allow recovery from badly set blockchain parameters without a hard fork
// (unless net_usage_leeway is set to 0 and so are the net limits of all accounts that can help with resetting blockchain parameters).

const static uint32_t   fixed_net_overhead_of_packed_trx = 16; // TODO: is this reasonable?

const static uint32_t   fixed_overhead_shared_vector_ram_bytes = 16; ///< overhead accounts for fixed portion of size of shared_vector field
const static uint32_t   overhead_per_row_per_index_ram_bytes = 32;    ///< overhead accounts for basic tracking structures in a row per index
const static uint32_t   overhead_per_account_ram_bytes     = 2*1024; ///< overhead accounts for basic account storage and pre-pays features like account recovery
const static uint32_t   setcode_ram_bytes_multiplier       = 10;     ///< multiplier on contract size to account for multiple copies and cached compilation

const static uint32_t   hashing_checktime_block_size       = 10*1024;  /// call checktime from hashing intrinsic once per this number of bytes

const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::binaryen;

/**
 *  The number of sequential blocks produced by a single producer
 */
const static int producer_repetitions = 12;
const static int max_producers = 125;

const static size_t maximum_tracked_dpos_confirmations = 1024;     ///<
static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1) * producer_repetitions, "Settings never allow for DPOS irreversibility" );

/**
 * The number of blocks produced per round is based upon all producers having a chance
 * to produce all of their consecutive blocks.
 */
//const static int blocks_per_round = producer_count * producer_repetitions;

const static int irreversible_threshold_percent= 70 * percent_1;

const static uint64_t billable_alignment = 16;

template<typename T>
struct billable_size;

template<typename T>
constexpr uint64_t billable_size_v = ((billable_size<T>::value + billable_alignment - 1) / billable_alignment) * billable_alignment;

} } } // namespace eosio::chain::config

constexpr uint64_t EOS_PERCENT(uint64_t value, uint32_t percentage) {
   return (value * percentage) / eosio::chain::config::percent_100;
}

template<typename Number>
Number EOS_PERCENT_CEIL(Number value, uint32_t percentage) {
   return ((value * percentage) + eosio::chain::config::percent_100 - eosio::chain::config::percent_1)  / eosio::chain::config::percent_100;
}
<commit_msg>default_target_block_cpu_usage_pct increased to 10% #3694<commit_after>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <fc/time.hpp>

#pragma GCC diagnostic ignored "-Wunused-variable"

namespace eosio { namespace chain { namespace config {

typedef __uint128_t uint128_t;

const static auto default_blocks_dir_name    = "blocks";
const static auto reversible_blocks_dir_name = "reversible";
const static auto default_reversible_cache_size = 340*1024*1024ll;/// 1MB * 340 blocks based on 21 producer BFT delay

const static auto default_state_dir_name     = "state";
const static auto forkdb_filename            = "forkdb.dat";
const static auto default_state_size            = 1*1024*1024*1024ll;

const static uint64_t system_account_name    = N(eosio);
const static uint64_t null_account_name      = N(eosio.null);
const static uint64_t producers_account_name = N(eosio.prods);

// Active permission of producers account requires greater than 2/3 of the producers to authorize
const static uint64_t majority_producers_permission_name = N(prod.major); // greater than 1/2 of producers needed to authorize
const static uint64_t minority_producers_permission_name = N(prod.minor); // greater than 1/3 of producers needed to authorize0

const static uint64_t eosio_auth_scope       = N(eosio.auth);
const static uint64_t eosio_all_scope        = N(eosio.all);

const static uint64_t active_name = N(active);
const static uint64_t owner_name  = N(owner);
const static uint64_t eosio_any_name = N(eosio.any);
const static uint64_t eosio_code_name = N(eosio.code);

const static int      block_interval_ms = 500;
const static int      block_interval_us = block_interval_ms*1000;
const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000.

/** Percentages are fixed point with a denominator of 10,000 */
const static int percent_100 = 10000;
const static int percent_1   = 100;

const static uint32_t  required_producer_participation = 33 * config::percent_1;

static const uint32_t account_cpu_usage_average_window_ms  = 24*60*60*1000l;
static const uint32_t account_net_usage_average_window_ms  = 24*60*60*1000l;
static const uint32_t block_cpu_usage_average_window_ms    = 60*1000l;
static const uint32_t block_size_average_window_ms         = 60*1000l;

//const static uint64_t   default_max_storage_size       = 10 * 1024;
//const static uint32_t   default_max_trx_runtime        = 10*1000;
//const static uint32_t   default_max_gen_trx_size       = 64 * 1024;

const static uint32_t   rate_limiting_precision        = 1000*1000;

const static uint32_t   default_max_block_net_usage                 = 1024 * 1024; /// at 500ms blocks and 200byte trx, this enables ~10,000 TPS burst
const static uint32_t   default_target_block_net_usage_pct           = 10 * percent_1; /// we target 1000 TPS
const static uint32_t   default_max_transaction_net_usage            = default_max_block_net_usage / 2;
const static uint32_t   default_base_per_transaction_net_usage       = 12;  // 12 bytes (11 bytes for worst case of transaction_receipt_header + 1 byte for static_variant tag)
const static uint32_t   default_net_usage_leeway                     = 500; // TODO: is this reasonable?
const static uint32_t   default_context_free_discount_net_usage_num  = 20; // TODO: is this reasonable?
const static uint32_t   default_context_free_discount_net_usage_den  = 100;
const static uint32_t   transaction_id_net_usage                     = 32; // 32 bytes for the size of a transaction id

const static uint32_t   default_max_block_cpu_usage                 = 200'000; /// max block cpu usage in microseconds
const static uint32_t   default_target_block_cpu_usage_pct          = 10 * percent_1;
const static uint32_t   default_max_transaction_cpu_usage           = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds
const static uint32_t   default_min_transaction_cpu_usage           = 100; /// min trx cpu usage in microseconds (10000 TPS equiv)

const static uint32_t   default_max_trx_lifetime               = 60*60; // 1 hour
const static uint32_t   default_deferred_trx_expiration_window = 10*60; // 10 minutes
const static uint32_t   default_max_trx_delay                  = 45*24*3600; // 45 days
const static uint32_t   default_max_inline_action_size         = 4 * 1024;   // 4 KB
const static uint16_t   default_max_inline_action_depth        = 4;
const static uint16_t   default_max_auth_depth                 = 6;

const static uint32_t   min_net_usage_delta_between_base_and_max_for_trx  = 10*1024;
// Should be large enough to allow recovery from badly set blockchain parameters without a hard fork
// (unless net_usage_leeway is set to 0 and so are the net limits of all accounts that can help with resetting blockchain parameters).

const static uint32_t   fixed_net_overhead_of_packed_trx = 16; // TODO: is this reasonable?

const static uint32_t   fixed_overhead_shared_vector_ram_bytes = 16; ///< overhead accounts for fixed portion of size of shared_vector field
const static uint32_t   overhead_per_row_per_index_ram_bytes = 32;    ///< overhead accounts for basic tracking structures in a row per index
const static uint32_t   overhead_per_account_ram_bytes     = 2*1024; ///< overhead accounts for basic account storage and pre-pays features like account recovery
const static uint32_t   setcode_ram_bytes_multiplier       = 10;     ///< multiplier on contract size to account for multiple copies and cached compilation

const static uint32_t   hashing_checktime_block_size       = 10*1024;  /// call checktime from hashing intrinsic once per this number of bytes

const static eosio::chain::wasm_interface::vm_type default_wasm_runtime = eosio::chain::wasm_interface::vm_type::binaryen;

/**
 *  The number of sequential blocks produced by a single producer
 */
const static int producer_repetitions = 12;
const static int max_producers = 125;

const static size_t maximum_tracked_dpos_confirmations = 1024;     ///<
static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1) * producer_repetitions, "Settings never allow for DPOS irreversibility" );

/**
 * The number of blocks produced per round is based upon all producers having a chance
 * to produce all of their consecutive blocks.
 */
//const static int blocks_per_round = producer_count * producer_repetitions;

const static int irreversible_threshold_percent= 70 * percent_1;

const static uint64_t billable_alignment = 16;

template<typename T>
struct billable_size;

template<typename T>
constexpr uint64_t billable_size_v = ((billable_size<T>::value + billable_alignment - 1) / billable_alignment) * billable_alignment;

} } } // namespace eosio::chain::config

constexpr uint64_t EOS_PERCENT(uint64_t value, uint32_t percentage) {
   return (value * percentage) / eosio::chain::config::percent_100;
}

template<typename Number>
Number EOS_PERCENT_CEIL(Number value, uint32_t percentage) {
   return ((value * percentage) + eosio::chain::config::percent_100 - eosio::chain::config::percent_1)  / eosio::chain::config::percent_100;
}
<|endoftext|>


<commit_before>#include "event_manager.hh"

#include <unistd.h>

namespace Kakoune
{

FDWatcher::FDWatcher(int fd, Callback callback)
    : m_fd{fd}, m_callback{std::move(callback)}
{
    EventManager::instance().m_fd_watchers.insert(this);
}

FDWatcher::~FDWatcher()
{
    EventManager::instance().m_fd_watchers.erase(this);
}

void FDWatcher::run(EventMode mode)
{
    m_callback(*this, mode);
}

void FDWatcher::close_fd()
{
    close(m_fd);
    m_fd = -1;
}

Timer::Timer(TimePoint date, Callback callback, EventMode mode)
    : m_date{date}, m_callback{std::move(callback)}, m_mode(mode)
{
    if (EventManager::has_instance())
        EventManager::instance().m_timers.insert(this);
}

Timer::~Timer()
{
    if (EventManager::has_instance())
        EventManager::instance().m_timers.erase(this);
}

void Timer::run(EventMode mode)
{
    if (mode == m_mode)
    {
        m_date = TimePoint::max();
        m_callback(*this);
    }
    else // try again a little later
        m_date = Clock::now() + std::chrono::milliseconds{10};
}

EventManager::EventManager()
{
    FD_ZERO(&m_forced_fd);
}

EventManager::~EventManager()
{
    kak_assert(m_fd_watchers.empty());
    kak_assert(m_timers.empty());
}

void EventManager::handle_next_events(EventMode mode)
{
    int max_fd = 0;
    fd_set rfds;
    FD_ZERO(&rfds);
    for (auto& watcher : m_fd_watchers)
    {
        const int fd = watcher->fd();
        if (fd != -1)
        {
            max_fd = std::max(fd, max_fd);
            FD_SET(fd, &rfds);
        }
    }

    TimePoint next_timer = TimePoint::max();
    for (auto& timer : m_timers)
    {
        if (timer->next_date() <= next_timer)
            next_timer = timer->next_date();
    }
    using namespace std::chrono;
    auto timeout = duration_cast<microseconds>(next_timer - Clock::now()).count();

    constexpr auto us = 1000000;
    // max timeout of 2 secs
    timeval tv{ (time_t)(timeout > us ? 1 : 0), (suseconds_t)(timeout % us) };
    int res = select(max_fd + 1, &rfds, nullptr, nullptr, &tv);

    // copy forced fds *after* poll, so that signal handlers can write to
    // m_forced_fd, interupt poll, and directly be serviced.
    fd_set forced = m_forced_fd;
    FD_ZERO(&m_forced_fd);

    for (int fd = 0; fd < max_fd + 1; ++fd)
    {
        if ((res > 0 and FD_ISSET(fd, &rfds)) or FD_ISSET(fd, &forced))
        {
            auto it = find_if(m_fd_watchers,
                              [fd](const FDWatcher* w){return w->fd() == fd; });
            if (it != m_fd_watchers.end())
                (*it)->run(mode);
        }
    }

    TimePoint now = Clock::now();
    for (auto& timer : m_timers)
    {
        if (timer->next_date() <= now)
            timer->run(mode);
    }
}

void EventManager::force_signal(int fd)
{
    FD_SET(fd, &m_forced_fd);
}

}
<commit_msg>Refactor (again) event handling, use proper infinite timeout<commit_after>#include "event_manager.hh"

#include <unistd.h>

namespace Kakoune
{

FDWatcher::FDWatcher(int fd, Callback callback)
    : m_fd{fd}, m_callback{std::move(callback)}
{
    EventManager::instance().m_fd_watchers.insert(this);
}

FDWatcher::~FDWatcher()
{
    EventManager::instance().m_fd_watchers.erase(this);
}

void FDWatcher::run(EventMode mode)
{
    m_callback(*this, mode);
}

void FDWatcher::close_fd()
{
    close(m_fd);
    m_fd = -1;
}

Timer::Timer(TimePoint date, Callback callback, EventMode mode)
    : m_date{date}, m_callback{std::move(callback)}, m_mode(mode)
{
    if (EventManager::has_instance())
        EventManager::instance().m_timers.insert(this);
}

Timer::~Timer()
{
    if (EventManager::has_instance())
        EventManager::instance().m_timers.erase(this);
}

void Timer::run(EventMode mode)
{
    if (mode == m_mode)
    {
        m_date = TimePoint::max();
        m_callback(*this);
    }
    else // try again a little later
        m_date = Clock::now() + std::chrono::milliseconds{10};
}

EventManager::EventManager()
{
    FD_ZERO(&m_forced_fd);
}

EventManager::~EventManager()
{
    kak_assert(m_fd_watchers.empty());
    kak_assert(m_timers.empty());
}

void EventManager::handle_next_events(EventMode mode)
{
    int max_fd = 0;
    fd_set rfds;
    FD_ZERO(&rfds);
    for (auto& watcher : m_fd_watchers)
    {
        const int fd = watcher->fd();
        if (fd != -1)
        {
            max_fd = std::max(fd, max_fd);
            FD_SET(fd, &rfds);
        }
    }

    timeval tv{};
    if (not m_timers.empty())
    {
        auto next = std::min_element(
            m_timers.begin(), m_timers.end(), [](Timer* lhs, Timer* rhs) {
                return lhs->next_date() < rhs->next_date();
        });
        using namespace std::chrono; using us = std::chrono::microseconds;
        auto usecs = std::max(us(0), duration_cast<us>((*next)->next_date() - Clock::now()));
        auto secs = duration_cast<seconds>(usecs);
        tv = timeval{ (time_t)secs.count(), (suseconds_t)(usecs - secs).count() };
    }
    int res = select(max_fd + 1, &rfds, nullptr, nullptr,
                     m_timers.empty() ? nullptr : &tv);

    // copy forced fds *after* poll, so that signal handlers can write to
    // m_forced_fd, interupt poll, and directly be serviced.
    fd_set forced = m_forced_fd;
    FD_ZERO(&m_forced_fd);

    for (int fd = 0; fd < max_fd + 1; ++fd)
    {
        if ((res > 0 and FD_ISSET(fd, &rfds)) or FD_ISSET(fd, &forced))
        {
            auto it = find_if(m_fd_watchers,
                              [fd](const FDWatcher* w){return w->fd() == fd; });
            if (it != m_fd_watchers.end())
                (*it)->run(mode);
        }
    }

    TimePoint now = Clock::now();
    for (auto& timer : m_timers)
    {
        if (timer->next_date() <= now)
            timer->run(mode);
    }
}

void EventManager::force_signal(int fd)
{
    FD_SET(fd, &m_forced_fd);
}

}
<|endoftext|>


<commit_before>//
//  fdf2nii_main.cpp
//
//  Created by Tobias Wood on 29/08/2013.
//
//

#include <string>
#include <iostream>
#include <iterator>
#include <getopt.h>

#include "fdf.h"
#include "Nifti.h"

using namespace std;

static bool zip = false, procpar = false;
static double scale = 1.;
static string outPrefix;
static struct option long_options[] =
{
	{"scale", required_argument, 0, 's'},
	{"out", required_argument, 0, 'o'},
	{"zip", no_argument, 0, 'z'},
	{"procpar", no_argument, 0, 'p'},
	{0, 0, 0, 0}
};

const string usage {
"fdf2nii - A utility to convert Agilent fdf files to nifti.\n\
\n\
Usage: fdf2nii [opts] image1 image2 ... imageN\n\
image1 to imageN are paths to the Agilent .img folders, not individual .fdf\n\
files\n\
Options:\n\
 -s, --scale:   Scale factor for image dimensions (set to 10 for use with SPM).\n\
 -o, --out:     Specify an output prefix.\n\
 -z, --zip:     Create .nii.gz files\n\
 -p, --procpar: Embed procpar in the nifti header.\n"
};

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "s:o:zp", long_options, &indexptr)) != -1) {
		switch (c) {
			case 0: break; // It was an option that just sets a flag.
			case 's': scale = atof(optarg); break;
			case 'o': outPrefix = string(optarg); break;
			case 'z': zip = true; break;
			case 'p': procpar = true; break;
			default: cout << "Unknown option " << optarg << endl;
		}
	}

	if ((argc - optind) <= 0) {
		cout << "No input images specified." << endl << usage << endl;
		exit(EXIT_FAILURE);
	}
	while (optind < argc) {
		string inPath(argv[optind]);
		optind++;
		size_t fileSep = inPath.find_last_of("/") + 1;
		size_t fileExt = inPath.find_last_of(".");
		if (inPath.substr(fileExt) != ".img") {
			cerr << inPath << " is not a valid .img folder. Skipping." << endl;
			continue;
		}
		string outPath = outPrefix + inPath.substr(fileSep, fileExt - fileSep) + ".nii";

		if (zip)
			outPath += ".gz";
		cout << "Converting " << inPath << " to " << outPath << endl;
		try {
			Agilent::fdfImage input(inPath);
			try {
				Nifti::File output(input.dim(0), input.dim(1), input.dim(2), input.dim(3),
								   input.voxdim(0) * scale, input.voxdim(1) * scale, input.voxdim(2) * scale, 1.,
								   DT_FLOAT32, input.ijk_to_xyz().cast<float>());
				if (procpar) {
					ifstream pp_file(inPath + "/procpar", ios::binary);
					pp_file.seekg(ios::end);
					size_t fileSize = pp_file.tellg();
					pp_file.seekg(ios::beg);
					vector<char> data; data.reserve(fileSize);
					data.assign(istreambuf_iterator<char>(pp_file), istreambuf_iterator<char>());
					output.addExtension(NIFTI_ECODE_COMMENT, data);
				}
				output.open(outPath, Nifti::Modes::Write);
				for (size_t v = 0; v < input.dim(3); v++) {
					output.writeVolume<float>(v, input.readVolume<float>(v));
				}
				output.close();
			} catch (exception &e) {
				cerr << "Error, skipping to next input. " << e.what() << outPath << endl;
				continue;
			}
		} catch (exception &e) {
			cerr << "Error, skipping to next input. " << e.what() << endl;
			continue;
		}
	}
    return EXIT_SUCCESS;
}
<commit_msg>Added options to control how multi-echo files are dealt with. Added a verbose option and an extra output per volume.<commit_after>//
//  fdf2nii_main.cpp
//
//  Created by Tobias Wood on 29/08/2013.
//
//

#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <getopt.h>

#include "fdf.h"
#include "Nifti.h"

using namespace std;

static bool zip = false, procpar = false, verbose = false;
static int echoMode = -1;
static double scale = 1.;
static string outPrefix;
static struct option long_options[] =
{
	{"scale", required_argument, 0, 's'},
	{"out", required_argument, 0, 'o'},
	{"zip", no_argument, 0, 'z'},
	{"echo", required_argument, 0, 'e'},
	{"procpar", no_argument, 0, 'p'},
	{"verbose", no_argument, 0, 'v'},
	{0, 0, 0, 0}
};

const string usage {
"fdf2nii - A utility to convert Agilent fdf files to nifti.\n\
\n\
Usage: fdf2nii [opts] image1 image2 ... imageN\n\
image1 to imageN are paths to the Agilent .img folders, not individual .fdf\n\
files\n\
Options:\n\
 -s, --scale:   Scale factor for image dimensions (set to 10 for use with SPM).\n\
 -o, --out:     Specify an output prefix.\n\
 -z, --zip:     Create .nii.gz files\n\
 -e, --echo N:  Choose echo N in a multiple echo file. Valid values for N are:\n\
                0..max echo   Write out just this echo\n\
				-1 (default)  Write out all echoes as individual images.\n\
				-2            Average echoes\n\
				If an echo is chosen beyond the maximum nothing is written.\n\
 -p, --procpar: Embed procpar in the nifti header.\n\
 -v, --verbose: Print out extra info (e.g. after each volume is written).\n"
};

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "s:o:ze:pv", long_options, &indexptr)) != -1) {
		switch (c) {
			case 0: break; // It was an option that just sets a flag.
			case 's': scale = atof(optarg); break;
			case 'o': outPrefix = string(optarg); break;
			case 'z': zip = true; break;
			case 'e': echoMode = atoi(optarg); break;
			case 'p': procpar = true; break;
			case 'v': verbose = true; break;
			default: cout << "Unknown option " << optarg << endl;
		}
	}

	if ((argc - optind) <= 0) {
		cout << "No input images specified." << endl << usage << endl;
		exit(EXIT_FAILURE);
	}
	while (optind < argc) {
		string inPath(argv[optind]);
		optind++;
		size_t fileSep = inPath.find_last_of("/") + 1;
		size_t fileExt = inPath.find_last_of(".");
		if (inPath.substr(fileExt) != ".img") {
			cerr << inPath << " is not a valid .img folder. Skipping." << endl;
			continue;
		}
		string outPath = outPrefix + inPath.substr(fileSep, fileExt - fileSep) + ".nii";

		if (zip)
			outPath += ".gz";
		if (verbose)
			cout << "Converting " << inPath << " to " << outPath << "..." << endl;
		try {
			Agilent::fdfImage input(inPath);
			size_t nOutImages = input.dim(3);
			if (echoMode == -1) {
				nOutImages *= input.dim(4);
			} else if ((echoMode >= 0) && (echoMode >= input.dim(4))) {
				throw(invalid_argument("Selected echo was above the maximum."));
			}
			try {
				Nifti::File output(input.dim(0), input.dim(1), input.dim(2), nOutImages,
								   input.voxdim(0) * scale, input.voxdim(1) * scale, input.voxdim(2) * scale, 1.,
								   DT_FLOAT32, input.ijk_to_xyz().cast<float>());
				if (procpar) {
					ifstream pp_file(inPath + "/procpar", ios::binary);
					pp_file.seekg(ios::end);
					size_t fileSize = pp_file.tellg();
					pp_file.seekg(ios::beg);
					vector<char> data; data.reserve(fileSize);
					data.assign(istreambuf_iterator<char>(pp_file), istreambuf_iterator<char>());
					output.addExtension(NIFTI_ECODE_COMMENT, data);
				}
				output.open(outPath, Nifti::Modes::Write);
				size_t outVol = 0;
				for (size_t inVol = 0; inVol < input.dim(3); inVol++) {
					if (echoMode >= 0) {
						output.writeVolume<float>(outVol++, input.readVolume<float>(inVol, echoMode));
					} else if (echoMode == -1) {
						for (size_t e = 0; e < input.dim(4); e++) {
							output.writeVolume<float>(outVol++, input.readVolume<float>(inVol, e));
						}
					} else if (echoMode == -2) {
						vector<float> sum = input.readVolume<float>(inVol, 0);
						for (size_t e = 1; e < input.dim(4); e++) {
							vector<float> data = input.readVolume<float>(inVol, e);
							transform(sum.begin(), sum.end(), data.begin(), sum.begin(), plus<float>());
						}
						output.writeVolume<float>(outVol++, sum);
					}
					if (verbose)
						cout << "Wrote volume " << outVol << " of " << nOutImages << endl;
				}
				output.close();
			} catch (exception &e) {
				cerr << "Error, skipping to next input. " << e.what() << outPath << endl;
				continue;
			}
		} catch (exception &e) {
			cerr << "Error, skipping to next input. " << e.what() << endl;
			continue;
		}
		if (verbose)
			cout << "Finished writing file " << outPath << endl;
	}
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "GameScreenState.h"
#include <algorithm>
#include <SFML/Graphics.hpp>

//const int TOP = 1;
//const int BOTTOM = 2;
//const int LEFT = 4;
//const int RIGHT = 8;
const unsigned char TOP = 0;
const unsigned char BOTTOM = 1;
const unsigned char LEFT = 2;
const unsigned char RIGHT = 3;

inline float clamp(float x, float min, float max) {
	 return std::max(std::min(x, max), min);
}

GameScreenState::GameScreenState() {
	advancement = 0;
	my_color = 1;
	resetPos();
	updateSprites();
}

void GameScreenState::resetPos() {
	pos = level.check_pos[advancement];
	velocity = sf::Vector2f(0, 0);
	acceleration = sf::Vector2f(0, 0);
	for (unsigned char i = 0; i < 4; i++) touching_walls[i] = 0;
}

void GameScreenState::event(const sf::RenderTarget& target, const sf::Event& event) {
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) {
		my_color = (my_color + 1) % 3;
		updateSprites();
	}
	m_editor.push_event(target, event);
}

void GameScreenState::updateSprites() {
	sprites.clear();
	sprites.resize(1);

	sf::RectangleShape sprite;
	sprite.setSize(sf::Vector2f(40, 40));
	//sprite.setFillColor(sf::Color::Red);
	const sf::Color colors[3] = {sf::Color::Blue, sf::Color::Black, sf::Color::Yellow};
	sprite.setFillColor(colors[my_color]);
	sprite.setPosition(pos - sf::Vector2f(20, 20));
	sprites.push_back(sprite);
}

void GameScreenState::updateView(sf::RenderTarget& target) {
	sf::Vector2f size = (sf::Vector2f)target.getSize();
	sf::Vector2f center
		(clamp(pos.x, level.bbox.minp.x + size.x / 2,
			level.bbox.maxp.x - size.x / 2),
		clamp(pos.y, level.bbox.minp.y + size.y / 2,
			level.bbox.maxp.y - size.y / 2));
	m_view.setCenter(center);
	m_view.setSize(size);
	target.setView(m_view);
}

void GameScreenState::render(sf::RenderTarget& target) {
	updateSprites();
	updateView(target);
	target.clear(sf::Color::White);
	level.render(target);
	for (unsigned int i = 0; i < sprites.size(); i++) {
		target.draw(sprites[i]);
	}
	m_editor.render(target);
}

const float TIME_SPEED = 1;
void GameScreenState::update(const sf::Time& time) {
	float s = time.asSeconds() * TIME_SPEED;
	sf::Vector2f offset = velocity * s + ((float) 0.5) * s * s * acceleration;
	pos += offset;
	m_view.move(offset);
	sf::Vector2f oldv = velocity + ((float) 0.5) * s * acceleration;
	velocity += s * acceleration;
	acceleration = sf::Vector2f(0, 240);
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
		velocity.x = std::min(velocity.x + (float)400 * s, (float)200);
    } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
		velocity.x = std::max(velocity.x - (float)400 * s, (float)-200);
	} else {
		//velocity.x = 0;
	}
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
		switch (touching_walls[BOTTOM]) {
			case 1:
				velocity.y -= 500 * s;
				break;
			case 2:
			case 3:
				velocity.y -= 150;
		}
	}
	velocity.x = std::max(std::min(velocity.x, (float)1500), (float)-1500);
	velocity.y = std::max(std::min(velocity.y, (float)1500), (float)-1500);
	rectangle me_ex = rectangle(pos - sf::Vector2f(20, 19.9), pos + sf::Vector2f(20, 19.9));
	rectangle me_ey = rectangle(pos - sf::Vector2f(19.9, 20), pos + sf::Vector2f(19.9, 20));
	rectangle me = rectangle(pos - sf::Vector2f(20, 20), pos + sf::Vector2f(20, 20));
	for (unsigned char i = 0; i < 4; i++) touching_walls[i] = 0;
	#define icolor(box) ((unsigned char)(((box).color - my_color + 3) % 3 + 1))
	for (unsigned int i = 0; i < level.boxes.size(); i++) {
		if (icolor(level.boxes[i]) < 2) continue; // Not solid
		if (level.boxes[i].intersects(me_ex)) {
			if (me_ey.maxp.x >= level.boxes[i].maxp.x) {
				if (me_ey.minp.x >= level.boxes[i].maxp.x + oldv.x * s) {
					float d = std::max(level.boxes[i].maxp.x - me_ex.minp.x, (float)0);
					pos.x += d;
					m_view.move(d,0);
					me_ex.movex(d);
					me_ey.movex(d);
				}
			}
			if (me_ey.minp.x <= level.boxes[i].minp.x) {
				if (me_ey.maxp.x <= level.boxes[i].minp.x + oldv.x * s) {
					float d = std::min(level.boxes[i].minp.x - me_ex.maxp.x, (float)0);
					pos.x += d;
					m_view.move(d,0);
					me_ex.movex(d);
					me_ey.movex(d);
				}
			}
		}
		if (level.boxes[i].intersects(me_ey)) {
			if (me_ex.maxp.y >= level.boxes[i].maxp.y) {
				if (me_ex.minp.y >= level.boxes[i].maxp.y + oldv.y * s) {
					float d = std::max(level.boxes[i].maxp.y - me_ey.minp.y, (float)0);
					pos.y += d;
					m_view.move(0.f,d);
					me_ex.movey(d);
					me_ey.movey(d);
				}
			}
			if (me_ex.minp.y <= level.boxes[i].minp.y) {
				if (me_ex.maxp.y <= level.boxes[i].minp.y + oldv.y * s) {
					float d = std::min(level.boxes[i].minp.y - me_ey.maxp.y, (float)0);
					pos.y += d;
					m_view.move(0.f,d);
					me_ex.movey(d);
					me_ey.movey(d);
				}
			}
		}
	}

	for (unsigned int i = 0; i < level.boxes.size(); i++) {
		if (level.boxes[i].intersects(me_ex)) {
			if (me_ey.minp.x >= level.boxes[i].minp.x) {
				touching_walls[LEFT] = std::max(touching_walls[LEFT], icolor(level.boxes[i]));
			}
			if (me_ey.maxp.x <= level.boxes[i].maxp.x) {
				touching_walls[RIGHT] = std::max(touching_walls[RIGHT], icolor(level.boxes[i]));
			}
		}
		if (level.boxes[i].intersects(me_ey)) {
			if (me_ex.minp.y >= level.boxes[i].minp.y) {
				touching_walls[TOP] = std::max(touching_walls[TOP], icolor(level.boxes[i]));
			}
			if (me_ex.maxp.y <= level.boxes[i].maxp.y) {
				touching_walls[BOTTOM] = std::max(touching_walls[BOTTOM], icolor(level.boxes[i]));
			}
		}
	}
	float visc = 0.01;
	switch (touching_walls[LEFT]) {
		case 1:
			if (velocity.x < 0) velocity.x *= pow(visc, s);
			break;
		case 2:
			velocity.x = std::max(velocity.x, (float)0);
			acceleration.x = std::max(acceleration.x, (float)0);
			break;
		case 3:
			velocity.x = std::max(velocity.x, -velocity.x);
			acceleration.x = std::max(acceleration.x, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[RIGHT]) {
		case 1:
			if (velocity.x > 0) velocity.x *= pow(visc, s);
			break;
		case 2:
			velocity.x = std::min(velocity.x, (float)0);
			acceleration.x = std::min(acceleration.x, (float)0);
			break;
		case 3:
			velocity.x = std::min(velocity.x, -velocity.x);
			acceleration.x = std::min(acceleration.x, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[TOP]) {
		case 1:
			if (velocity.y < 0) velocity.y *= pow(visc, s);
			break;
		case 2:
			velocity.y = std::max(velocity.y, (float)0);
			acceleration.y = std::max(acceleration.y, (float)0);
			break;
		case 3:
			velocity.y = std::max(velocity.y, -velocity.y);
			acceleration.y = std::max(acceleration.y, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[BOTTOM]) {
		case 1:
			if (velocity.y > 0) velocity.y *= pow(visc, s);
			break;
		case 2:
			velocity.y = std::min(velocity.y, (float)0);
			acceleration.y = std::min(acceleration.y, (float)0);
			if (velocity.x > 0) {
				velocity.x = std::max((float)0, velocity.x - (float)100 * s);
			} else {
				velocity.x = std::min((float)0, velocity.x + (float)100 * s);
			}
			break;
		case 3:
			velocity.y = std::min(velocity.y, -velocity.y);
			acceleration.y = std::min(acceleration.y, (float)0);
			break;
		default: break;
	}
	velocity.x *= pow(0.2, s);

	rectangle checkpoint = rectangle(-10, -10, 10, 10);
	for (unsigned int i = level.check_pos.size() - 1; i > advancement; i--) {
		if (me.intersects(checkpoint + level.check_pos[i])) {
			advancement = i;
			break;
		}
	}

	if (pos.y > level.bbox.maxp.y) {
		kill();
	}
}

void GameScreenState::kill() {
	resetPos();
}

void GameScreenState::window_update(const sf::RenderWindow& window)
{
	m_editor.update_mouse(sf::Mouse::getPosition(window));
}
<commit_msg>Little ugly fix<commit_after>#include "GameScreenState.h"
#include <algorithm>
#include <SFML/Graphics.hpp>

//const int TOP = 1;
//const int BOTTOM = 2;
//const int LEFT = 4;
//const int RIGHT = 8;
const unsigned char TOP = 0;
const unsigned char BOTTOM = 1;
const unsigned char LEFT = 2;
const unsigned char RIGHT = 3;

inline float clamp(float x, float min, float max) {
	 return std::max(std::min(x, max), min);
}

GameScreenState::GameScreenState() {
	advancement = 0;
	my_color = 1;
	resetPos();
	updateSprites();
}

void GameScreenState::resetPos() {
	pos = level.check_pos[advancement];
	velocity = sf::Vector2f(0, 0);
	acceleration = sf::Vector2f(0, 0);
	for (unsigned char i = 0; i < 4; i++) touching_walls[i] = 0;
}

void GameScreenState::event(const sf::RenderTarget& target, const sf::Event& event) {
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) {
		my_color = (my_color + 1) % 3;
		updateSprites();
	}
	m_editor.push_event(target, event);
}

void GameScreenState::updateSprites() {
	sprites.clear();
	sprites.resize(1);

	sf::RectangleShape sprite;
	sprite.setSize(sf::Vector2f(40, 40));
	//sprite.setFillColor(sf::Color::Red);
	const sf::Color colors[3] = {sf::Color::Blue, sf::Color::Black, sf::Color::Yellow};
	sprite.setFillColor(colors[my_color]);
	sprite.setPosition(pos - sf::Vector2f(20, 20));
	sprites.push_back(sprite);
}

void GameScreenState::updateView(sf::RenderTarget& target) {
	sf::Vector2f size = (sf::Vector2f)target.getSize();
	sf::Vector2f center
		(clamp(pos.x, level.bbox.minp.x + size.x / 2,
			level.bbox.maxp.x - size.x / 2),
		clamp(pos.y, level.bbox.minp.y + size.y / 2,
			level.bbox.maxp.y - size.y / 2));
	m_view.setCenter(center);
	m_view.setSize(size);
	target.setView(m_view);
}

void GameScreenState::render(sf::RenderTarget& target) {
	updateSprites();
	updateView(target);
	target.clear(sf::Color::White);
	level.render(target);
	for (unsigned int i = 0; i < sprites.size(); i++) {
		target.draw(sprites[i]);
	}
	m_editor.render(target);
}

const float TIME_SPEED = 1;
void GameScreenState::update(const sf::Time& time) {
	float s = time.asSeconds() * TIME_SPEED;
	sf::Vector2f offset = velocity * s + ((float) 0.5) * s * s * acceleration;
	pos += offset;
	m_view.move(offset);
	sf::Vector2f oldv = velocity + ((float) 0.5) * s * acceleration;
	velocity += s * acceleration;
	acceleration = sf::Vector2f(0, 240);
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
		velocity.x = std::min(velocity.x + (float)400 * s, (float)200);
    } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
		velocity.x = std::max(velocity.x - (float)400 * s, (float)-200);
	} else {
		//velocity.x = 0;
	}
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
		switch (touching_walls[BOTTOM]) {
			case 1:
				velocity.y -= 500 * s;
				break;
			case 2:
			case 3:
				velocity.y -= 150;
		}
	}
	velocity.x = std::max(std::min(velocity.x, (float)1500), (float)-1500);
	velocity.y = std::max(std::min(velocity.y, (float)1500), (float)-1500);
	rectangle me_ex = rectangle(pos - sf::Vector2f(20, 19.9), pos + sf::Vector2f(20, 19.9));
	rectangle me_ey = rectangle(pos - sf::Vector2f(19.9, 20), pos + sf::Vector2f(19.9, 20));
	rectangle me = rectangle(pos - sf::Vector2f(20, 20), pos + sf::Vector2f(20, 20));
	for (unsigned char i = 0; i < 4; i++) touching_walls[i] = 0;
	#define icolor(box) ((unsigned char)(((box).color - my_color + 3) % 3 + 1))
	for (unsigned int i = 0; i < level.boxes.size(); i++) {
		if (icolor(level.boxes[i]) < 2) continue; // Not solid
		if (level.boxes[i].intersects(me_ex)) {
			if (me_ey.maxp.x >= level.boxes[i].maxp.x) {
				if (me_ey.minp.x >= level.boxes[i].maxp.x + oldv.x * s) {
					float d = std::max(level.boxes[i].maxp.x - me_ex.minp.x, (float)0);
					pos.x += d;
					m_view.move(d,0);
					me_ex.movex(d);
					me_ey.movex(d);
				}
			}
			if (me_ey.minp.x <= level.boxes[i].minp.x) {
				if (me_ey.maxp.x <= level.boxes[i].minp.x + oldv.x * s) {
					float d = std::min(level.boxes[i].minp.x - me_ex.maxp.x, (float)0);
					pos.x += d;
					m_view.move(d,0);
					me_ex.movex(d);
					me_ey.movex(d);
				}
			}
		}
		if (level.boxes[i].intersects(me_ey)) {
			if (me_ex.maxp.y >= level.boxes[i].maxp.y) {
				if (me_ex.minp.y >= level.boxes[i].maxp.y + oldv.y * s) {
					float d = std::max(level.boxes[i].maxp.y - me_ey.minp.y, (float)0);
					pos.y += d;
					m_view.move(0.f,d);
					me_ex.movey(d);
					me_ey.movey(d);
				}
			}
			if (me_ex.minp.y <= level.boxes[i].minp.y) {
				if (me_ex.maxp.y <= level.boxes[i].minp.y + oldv.y * s) {
					float d = std::min(level.boxes[i].minp.y - me_ey.maxp.y, (float)0);
					pos.y += d;
					m_view.move(0.f,d);
					me_ex.movey(d);
					me_ey.movey(d);
				}
			}
		}
	}

	for (unsigned int i = 0; i < level.boxes.size(); i++) {
		if (level.boxes[i].intersects(me_ex)) {
			if (me_ey.minp.x >= level.boxes[i].minp.x) {
				touching_walls[LEFT] = std::max(touching_walls[LEFT], icolor(level.boxes[i]));
			}
			if (me_ey.maxp.x <= level.boxes[i].maxp.x) {
				touching_walls[RIGHT] = std::max(touching_walls[RIGHT], icolor(level.boxes[i]));
			}
		}
		if (level.boxes[i].intersects(me_ey)) {
			if (me_ex.minp.y >= level.boxes[i].minp.y) {
				touching_walls[TOP] = std::max(touching_walls[TOP], icolor(level.boxes[i]));
			}
			if (me_ex.maxp.y <= level.boxes[i].maxp.y) {
				touching_walls[BOTTOM] = std::max(touching_walls[BOTTOM], icolor(level.boxes[i]));
			}
		}
	}
	float visc = 0.01;
	switch (touching_walls[LEFT]) {
		case 1:
			if (velocity.x < 0) velocity.x *= pow(visc, s);
			break;
		case 2:
			velocity.x = std::max(velocity.x, (float)0);
			acceleration.x = std::max(acceleration.x, (float)0);
			break;
		case 3:
			velocity.x = std::max(velocity.x, -velocity.x);
			acceleration.x = std::max(acceleration.x, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[RIGHT]) {
		case 1:
			if (velocity.x > 0) velocity.x *= pow(visc, s);
			break;
		case 2:
			velocity.x = std::min(velocity.x, (float)0);
			acceleration.x = std::min(acceleration.x, (float)0);
			break;
		case 3:
			velocity.x = std::min(velocity.x, -velocity.x);
			acceleration.x = std::min(acceleration.x, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[TOP]) {
		case 1:
			if (velocity.y < 0) velocity.y *= pow(visc, s);
			break;
		case 2:
			velocity.y = std::max(velocity.y, (float)0);
			acceleration.y = std::max(acceleration.y, (float)0);
			break;
		case 3:
			velocity.y = std::max(velocity.y, -velocity.y);
			acceleration.y = std::max(acceleration.y, (float)0);
			break;
		default: break;
	}
	switch (touching_walls[BOTTOM]) {
		case 1:
			if (velocity.y > 0) velocity.y *= pow(visc, s);
			break;
		case 2:
			velocity.y = std::min(velocity.y, (float)0);
			acceleration.y = std::min(acceleration.y, (float)0);
			if (velocity.x > 0) {
				velocity.x = std::max((float)0, velocity.x - (float)100 * s);
			} else {
				velocity.x = std::min((float)0, velocity.x + (float)100 * s);
			}
			break;
		case 3:
			velocity.y = std::min(velocity.y, -velocity.y);
			acceleration.y = std::min(acceleration.y, (float)0);
			break;
		default: break;
	}
	if (touching_walls[TOP] >= 2 && touching_walls[BOTTOM] >= 2) {
		velocity.y = 0;
		acceleration.y = 0;
	}
	if (touching_walls[LEFT] >= 2 && touching_walls[RIGHT] >= 2) {
		velocity.x = 0;
		acceleration.x = 0;
	}

	velocity.x *= pow(0.2, s);

	rectangle checkpoint = rectangle(-10, -10, 10, 10);
	for (unsigned int i = level.check_pos.size() - 1; i > advancement; i--) {
		if (me.intersects(checkpoint + level.check_pos[i])) {
			advancement = i;
			break;
		}
	}

	if (pos.y > level.bbox.maxp.y) {
		kill();
	}
}

void GameScreenState::kill() {
	resetPos();
}

void GameScreenState::window_update(const sf::RenderWindow& window)
{
	m_editor.update_mouse(sf::Mouse::getPosition(window));
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include <climits>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"

namespace {

const int kTestMode = 0;
const int kSuperframeSyntax = 1;
const int kTileCols = 2;
const int kTileRows = 3;

typedef std::tr1::tuple<libvpx_test::TestMode, int,
                        int, int> SuperframeTestParam;

class SuperframeTest : public ::libvpx_test::EncoderTest,
    public ::libvpx_test::CodecTestWithParam<SuperframeTestParam> {
 protected:
  SuperframeTest() : EncoderTest(GET_PARAM(0)), modified_buf_(NULL),
      last_sf_pts_(0) {}
  virtual ~SuperframeTest() {}

  virtual void SetUp() {
    InitializeConfig();
    const SuperframeTestParam input = GET_PARAM(1);
    const libvpx_test::TestMode mode = std::tr1::get<kTestMode>(input);
    const int syntax = std::tr1::get<kSuperframeSyntax>(input);
    SetMode(mode);
    sf_count_ = 0;
    sf_count_max_ = INT_MAX;
    is_vp10_style_superframe_ = syntax;
    n_tile_cols_ = std::tr1::get<kTileCols>(input);
    n_tile_rows_ = std::tr1::get<kTileRows>(input);
  }

  virtual void TearDown() {
    delete[] modified_buf_;
  }

  virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
                                  libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
      encoder->Control(VP8E_SET_CPUUSED, 2);
      encoder->Control(VP9E_SET_TILE_COLUMNS, n_tile_cols_);
      encoder->Control(VP9E_SET_TILE_ROWS, n_tile_rows_);
    }
  }

  virtual const vpx_codec_cx_pkt_t * MutateEncoderOutputHook(
      const vpx_codec_cx_pkt_t *pkt) {
    if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
      return pkt;

    const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
    const uint8_t marker = buffer[pkt->data.frame.sz - 1];
    const int frames = (marker & 0x7) + 1;
    const int mag = ((marker >> 3) & 3) + 1;
    const unsigned int index_sz =
        2 + mag * (frames - is_vp10_style_superframe_);
    if ((marker & 0xe0) == 0xc0 &&
        pkt->data.frame.sz >= index_sz &&
        buffer[pkt->data.frame.sz - index_sz] == marker) {
      // frame is a superframe. strip off the index.
      if (modified_buf_)
        delete[] modified_buf_;
      modified_buf_ = new uint8_t[pkt->data.frame.sz - index_sz];
      memcpy(modified_buf_, pkt->data.frame.buf,
             pkt->data.frame.sz - index_sz);
      modified_pkt_ = *pkt;
      modified_pkt_.data.frame.buf = modified_buf_;
      modified_pkt_.data.frame.sz -= index_sz;

      sf_count_++;
      last_sf_pts_ = pkt->data.frame.pts;
      return &modified_pkt_;
    }

    // Make sure we do a few frames after the last SF
    abort_ |= sf_count_ > sf_count_max_ &&
              pkt->data.frame.pts - last_sf_pts_ >= 5;
    return pkt;
  }

  int is_vp10_style_superframe_;
  int sf_count_;
  int sf_count_max_;
  vpx_codec_cx_pkt_t modified_pkt_;
  uint8_t *modified_buf_;
  vpx_codec_pts_t last_sf_pts_;

 private:
  int n_tile_cols_;
  int n_tile_rows_;
};

TEST_P(SuperframeTest, TestSuperframeIndexIsOptional) {
  sf_count_max_ = 0;  // early exit on successful test.
  cfg_.g_lag_in_frames = 25;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 40);
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
  EXPECT_EQ(sf_count_, 1);
}

VP9_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(0), ::testing::Values(0), ::testing::Values(0)));

// The superframe index is currently mandatory with ANS due to the decoder
// starting at the end of the buffer.
#if CONFIG_EXT_TILE
// Single tile does not work with ANS (see comment above).
#if CONFIG_ANS
const int tile_col_values[] = { 1, 2 };
#else
const int tile_col_values[] = { 1, 2, 32 };
#endif
const int tile_row_values[] = { 1, 2, 32 };
VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(1),
    ::testing::ValuesIn(tile_col_values),
    ::testing::ValuesIn(tile_row_values)));
#else
#if !CONFIG_ANS
VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(1), ::testing::Values(0), ::testing::Values(0)));
#endif  // !CONFIG_ANS
#endif  // CONFIG_EXT_TILE
}  // namespace
<commit_msg>Fix the superframe unit test for BIDIR_PRED<commit_after>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include <climits>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"

namespace {

const int kTestMode = 0;
const int kSuperframeSyntax = 1;
const int kTileCols = 2;
const int kTileRows = 3;

typedef std::tr1::tuple<libvpx_test::TestMode, int,
                        int, int> SuperframeTestParam;

class SuperframeTest : public ::libvpx_test::EncoderTest,
    public ::libvpx_test::CodecTestWithParam<SuperframeTestParam> {
 protected:
  SuperframeTest() : EncoderTest(GET_PARAM(0)), modified_buf_(NULL),
      last_sf_pts_(0) {}
  virtual ~SuperframeTest() {}

  virtual void SetUp() {
    InitializeConfig();
    const SuperframeTestParam input = GET_PARAM(1);
    const libvpx_test::TestMode mode = std::tr1::get<kTestMode>(input);
    const int syntax = std::tr1::get<kSuperframeSyntax>(input);
    SetMode(mode);
    sf_count_ = 0;
    sf_count_max_ = INT_MAX;
    is_vp10_style_superframe_ = syntax;
    n_tile_cols_ = std::tr1::get<kTileCols>(input);
    n_tile_rows_ = std::tr1::get<kTileRows>(input);
  }

  virtual void TearDown() {
    delete[] modified_buf_;
  }

  virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
                                  libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
      encoder->Control(VP8E_SET_CPUUSED, 2);
      encoder->Control(VP9E_SET_TILE_COLUMNS, n_tile_cols_);
      encoder->Control(VP9E_SET_TILE_ROWS, n_tile_rows_);
    }
  }

  virtual const vpx_codec_cx_pkt_t * MutateEncoderOutputHook(
      const vpx_codec_cx_pkt_t *pkt) {
    if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
      return pkt;

    const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
    const uint8_t marker = buffer[pkt->data.frame.sz - 1];
    const int frames = (marker & 0x7) + 1;
    const int mag = ((marker >> 3) & 3) + 1;
    const unsigned int index_sz =
        2 + mag * (frames - is_vp10_style_superframe_);
    if ((marker & 0xe0) == 0xc0 &&
        pkt->data.frame.sz >= index_sz &&
        buffer[pkt->data.frame.sz - index_sz] == marker) {
      // frame is a superframe. strip off the index.
      if (modified_buf_)
        delete[] modified_buf_;
      modified_buf_ = new uint8_t[pkt->data.frame.sz - index_sz];
      memcpy(modified_buf_, pkt->data.frame.buf,
             pkt->data.frame.sz - index_sz);
      modified_pkt_ = *pkt;
      modified_pkt_.data.frame.buf = modified_buf_;
      modified_pkt_.data.frame.sz -= index_sz;

      sf_count_++;
      last_sf_pts_ = pkt->data.frame.pts;
      return &modified_pkt_;
    }

    // Make sure we do a few frames after the last SF
    abort_ |= sf_count_ > sf_count_max_ &&
              pkt->data.frame.pts - last_sf_pts_ >= 5;
    return pkt;
  }

  int is_vp10_style_superframe_;
  int sf_count_;
  int sf_count_max_;
  vpx_codec_cx_pkt_t modified_pkt_;
  uint8_t *modified_buf_;
  vpx_codec_pts_t last_sf_pts_;

 private:
  int n_tile_cols_;
  int n_tile_rows_;
};

TEST_P(SuperframeTest, TestSuperframeIndexIsOptional) {
  sf_count_max_ = 0;  // early exit on successful test.
  cfg_.g_lag_in_frames = 25;

  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                       30, 1, 0, 40);
  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
#if CONFIG_BIDIR_PRED
  // NOTE: The use of BWDREF_FRAME will enable the coding of more non-show
  //       frames besides ALTREF_FRAME.
  EXPECT_GE(sf_count_, 1);
#else
  EXPECT_EQ(sf_count_, 1);
#endif  // CONFIG_BIDIR_PRED
}

VP9_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(0), ::testing::Values(0), ::testing::Values(0)));

// The superframe index is currently mandatory with ANS due to the decoder
// starting at the end of the buffer.
#if CONFIG_EXT_TILE
// Single tile does not work with ANS (see comment above).
#if CONFIG_ANS
const int tile_col_values[] = { 1, 2 };
#else
const int tile_col_values[] = { 1, 2, 32 };
#endif
const int tile_row_values[] = { 1, 2, 32 };
VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(1),
    ::testing::ValuesIn(tile_col_values),
    ::testing::ValuesIn(tile_row_values)));
#else
#if !CONFIG_ANS
VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
    ::testing::Values(::libvpx_test::kTwoPassGood),
    ::testing::Values(1), ::testing::Values(0), ::testing::Values(0)));
#endif  // !CONFIG_ANS
#endif  // CONFIG_EXT_TILE
}  // namespace
<|endoftext|>


<commit_before>#include "taichi.h"  // Note: You DO NOT have to install taichi or taichi_mpm.
using namespace taichi;  // You only need [taichi.h] - see below for
                         // instructions.
const int n = 160 /*grid resolution (cells)*/, window_size = 800;
const real dt = 60e-4_f / n, frame_dt = 1e-3_f, dx = 1.0_f / n,
           inv_dx = 1.0_f / dx;
auto particle_mass = 1.0_f, vol = 1.0_f;
auto hardening = 10.0_f, E = 1e4_f, nu = 0.2_f;
real mu_0 = E / (2 * (1 + nu)), lambda_0 = E * nu / ((1 + nu) * (1 - 2 * nu));
using Vec = Vector2;
using Mat = Matrix2;

struct Particle {
  Vec x, v;
  Mat F, C;
  real Jp;
  int c /*color*/;
  int type;  // 0: elastic   1: plastic   2: liquid
  Particle(Vec x, int c, int type, Vec v = Vec(0))
      : x(x), v(v), F(1), C(0), Jp(1), c(c), type(type) {
  }
};
std::vector<Particle> particles;
Vector3 grid[n + 1][n + 1];  // velocity + mass, node_res = cell_res + 1

// http://zetcode.com/tutorials/javaswingtutorial/thetetrisgame/
int tetris_offsets[7][3][2] = {
    // excluding center
    {{0, -1}, {-1, 0}, {-2, 0}}, {{0, 1}, {-1, 0}, {-2, 0}},
    {{1, 0}, {-1, 0}, {1, 1}},   {{0, 1}, {1, 0}, {1, 1}},
    {{0, 1}, {0, -1}, {0, 2}},   {{0, 1}, {0, -1}, {0, 2}},
};

void advance(real dt) {
  std::memset(grid, 0, sizeof(grid));  // Reset grid
  for (auto &p : particles) {          // P2G
    Vector2i base_coord =
        (p.x * inv_dx - Vec(0.5_f)).cast<int>();  // element-wise floor
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    // Quadratic kernels  [http://mpm.graphics   Eqn. 123, with x=fx, fx-1,fx-2]
    Vec w[3]{Vec(0.5) * sqr(Vec(1.5) - fx), Vec(0.75) - sqr(fx - Vec(1.0)),
             Vec(0.5) * sqr(fx - Vec(0.5))};
    auto e = std::exp(hardening * (1.0_f - p.Jp)), mu = mu_0 * e,
         lambda = lambda_0 * e;
    real J = determinant(p.F);  //                         Current volume
    Mat r, s;
    polar_decomp(p.F, r, s);  // Polar decomp. for fixed corotated model
    Mat cauchy;
    if (p.type == 2) {
      cauchy = Mat(0.2_f * E * (pow<1>(p.Jp) - 1));
    } else {
      cauchy = 2 * mu * (p.F - r) * transposed(p.F) + lambda * (J - 1) * J;
    }
    auto stress =  // Cauchy stress times dt and inv_dx
        -4 * inv_dx * inv_dx * dt * vol * cauchy;
    auto affine = stress + particle_mass * p.C;
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++) {  // Scatter to grid
        auto dpos = (Vec(i, j) - fx) * dx;
        Vector3 mv(p.v * particle_mass,
                   particle_mass);  // translational momentum
        grid[base_coord.x + i][base_coord.y + j] +=
            w[i].x * w[j].y * (mv + Vector3(affine * dpos, 0));
      }
  }
  for (int i = 0; i <= n; i++)
    for (int j = 0; j <= n; j++) {  // For all grid nodes
      auto &g = grid[i][j];
      if (g[2] > 0) {                   // No need for epsilon here
        g /= g[2];                      //        Normalize by mass
        g += dt * Vector3(0, -200, 0);  //                  Gravity
        real boundary = 0.05, x = (real)i / n,
             y = real(j) / n;  // boundary thick.,node coord
        if (x < boundary || x > 1 - boundary || y > 1 - boundary)
          g = Vector3(0);  // Sticky
        if (y < boundary)
          g[1] = std::max(0.0_f, g[1]);  //"Separate"
      }
    }
  for (auto &p : particles) {  // Grid to particle
    Vector2i base_coord =
        (p.x * inv_dx - Vec(0.5_f)).cast<int>();  // element-wise floor
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    Vec w[3]{Vec(0.5) * sqr(Vec(1.5) - fx), Vec(0.75) - sqr(fx - Vec(1.0)),
             Vec(0.5) * sqr(fx - Vec(0.5))};
    p.C = Mat(0);
    p.v = Vec(0);
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx),
             grid_v = Vec(grid[base_coord.x + i][base_coord.y + j]);
        auto weight = w[i].x * w[j].y;
        p.v += weight * grid_v;  // Velocity
        p.C +=
            4 * inv_dx * Mat::outer_product(weight * grid_v, dpos);  // APIC C
      }
    p.x += dt * p.v;                       // Advection
    if (p.type <= 1) {                     // plastic
      auto F = (Mat(1) + dt * p.C) * p.F;  // MLS-MPM F-update
      if (p.type == 1) {
        Mat svd_u, sig, svd_v;
        svd(F, svd_u, sig, svd_v);
        for (int i = 0; i < 2; i++)  // Snow Plasticity
          sig[i][i] = clamp(sig[i][i], 1.0_f - 2.5e-2_f, 1.0_f + 7.5e-3_f);
        real oldJ = determinant(F);
        F = svd_u * sig * transposed(svd_v);
        real Jp_new = clamp(p.Jp * oldJ / determinant(F), 0.6_f, 20.0_f);
        p.Jp = Jp_new;
      }
      p.F = F;
    } else {  // liquid
      p.Jp *= determinant(Mat(1) + dt * p.C);
    }
  }
}

void add_object(Vec center, int c, int type, int block) {
  auto gen = [&](int k) {
    Vector2 offset(0, 0);
    if (k >= 0)
      offset =
          Vector2(tetris_offsets[block][k][0], tetris_offsets[block][k][1]);
    for (int i = 0; i < 30 * pow<2>(n / 80.0); i++)
      particles.push_back(
          Particle((Vec::rand() + offset) * 0.05_f + center, c, type));
  };
  gen(-1);
  gen(0);
  gen(1);
  gen(2);
}

int main() {
  GUI gui("Real-time 2D MLS-MPM", window_size, window_size);
  add_object(Vec(0.55, 0.45), 0xED553B, 0, 0);
  add_object(Vec(0.45, 0.65), 0xF2B134, 1, 1);
  add_object(Vec(0.55, 0.75), 0x068587, 2, 2);
  auto &canvas = gui.get_canvas();
  int f = 0;
  for (int i = 0;; i++) {               //              Main Loop
    advance(dt);                        //     Advance simulation
    if (i % int(frame_dt / dt) == 0) {  //        Visualize frame
      canvas.clear(0x112F41);           //       Clear background
      canvas.rect(Vec(0.04), Vec(0.96))
          .radius(2)
          .color(0x4FB99F)
          .close();  // Box
      for (auto p : particles)
        canvas.circle(p.x).radius(2).color(p.c);  // Particles
      gui.update();                               // Update image
      // canvas.img.write_as_image(fmt::format("tmp/{:05d}.png", f++));
    }
  }
}  //----------------------------------------------------------------------------

// g++ tetris.cpp -std=c++14 -g -lX11 -lpthread -O3 -o tetris && ./tetris<commit_msg>all shapes<commit_after>#include "taichi.h"  // Note: You DO NOT have to install taichi or taichi_mpm.
using namespace taichi;  // You only need [taichi.h] - see below for
                         // instructions.
const int n = 160 /*grid resolution (cells)*/, window_size = 800;
const real dt = 60e-4_f / n, frame_dt = 1e-3_f, dx = 1.0_f / n,
           inv_dx = 1.0_f / dx;
auto particle_mass = 1.0_f, vol = 1.0_f;
auto hardening = 10.0_f, E = 1e4_f, nu = 0.2_f;
real mu_0 = E / (2 * (1 + nu)), lambda_0 = E * nu / ((1 + nu) * (1 - 2 * nu));
using Vec = Vector2;
using Mat = Matrix2;

struct Particle {
  Vec x, v;
  Mat F, C;
  real Jp;
  int c /*color*/;
  int type;  // 0: elastic   1: plastic   2: liquid
  Particle(Vec x, int c, int type, Vec v = Vec(0))
      : x(x), v(v), F(1), C(0), Jp(1), c(c), type(type) {
  }
};
std::vector<Particle> particles;
Vector3 grid[n + 1][n + 1];  // velocity + mass, node_res = cell_res + 1

// http://zetcode.com/tutorials/javaswingtutorial/thetetrisgame/
int tetris_offsets[7][3][2] = {
    // excluding center
    {{0, -1}, {1, 0}, {0, -2}},  {{1, 1}, {-1, 0}, {1, 0}},
    {{0, -1}, {-1, 0}, {0, -2}}, {{0, 1}, {1, 0}, {1, -1}},
    {{1, 0}, {2, 0}, {-1, 0}},   {{0, 1}, {1, 1}, {1, 1}},
    {{-1, 0}, {1, 0}, {0, 1}}};

void advance(real dt) {
  std::memset(grid, 0, sizeof(grid));  // Reset grid
  for (auto &p : particles) {          // P2G
    Vector2i base_coord =
        (p.x * inv_dx - Vec(0.5_f)).cast<int>();  // element-wise floor
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    // Quadratic kernels  [http://mpm.graphics   Eqn. 123, with x=fx, fx-1,fx-2]
    Vec w[3]{Vec(0.5) * sqr(Vec(1.5) - fx), Vec(0.75) - sqr(fx - Vec(1.0)),
             Vec(0.5) * sqr(fx - Vec(0.5))};
    auto e = std::exp(hardening * (1.0_f - p.Jp)), mu = mu_0 * e,
         lambda = lambda_0 * e;
    real J = determinant(p.F);  //                         Current volume
    Mat r, s;
    polar_decomp(p.F, r, s);  // Polar decomp. for fixed corotated model
    Mat cauchy;
    if (p.type == 2) {
      cauchy = Mat(0.2_f * E * (pow<1>(p.Jp) - 1));
    } else {
      cauchy = 2 * mu * (p.F - r) * transposed(p.F) + lambda * (J - 1) * J;
    }
    auto stress =  // Cauchy stress times dt and inv_dx
        -4 * inv_dx * inv_dx * dt * vol * cauchy;
    auto affine = stress + particle_mass * p.C;
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++) {  // Scatter to grid
        auto dpos = (Vec(i, j) - fx) * dx;
        Vector3 mv(p.v * particle_mass,
                   particle_mass);  // translational momentum
        grid[base_coord.x + i][base_coord.y + j] +=
            w[i].x * w[j].y * (mv + Vector3(affine * dpos, 0));
      }
  }
  for (int i = 0; i <= n; i++)
    for (int j = 0; j <= n; j++) {  // For all grid nodes
      auto &g = grid[i][j];
      if (g[2] > 0) {                   // No need for epsilon here
        g /= g[2];                      //        Normalize by mass
        g += dt * Vector3(0, -200, 0);  //                  Gravity
        real boundary = 0.05, x = (real)i / n,
             y = real(j) / n;  // boundary thick.,node coord
        if (x < boundary || x > 1 - boundary || y > 1 - boundary)
          g = Vector3(0);  // Sticky
        if (y < boundary)
          g[1] = std::max(0.0_f, g[1]);  //"Separate"
      }
    }
  for (auto &p : particles) {  // Grid to particle
    Vector2i base_coord =
        (p.x * inv_dx - Vec(0.5_f)).cast<int>();  // element-wise floor
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    Vec w[3]{Vec(0.5) * sqr(Vec(1.5) - fx), Vec(0.75) - sqr(fx - Vec(1.0)),
             Vec(0.5) * sqr(fx - Vec(0.5))};
    p.C = Mat(0);
    p.v = Vec(0);
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx),
             grid_v = Vec(grid[base_coord.x + i][base_coord.y + j]);
        auto weight = w[i].x * w[j].y;
        p.v += weight * grid_v;  // Velocity
        p.C +=
            4 * inv_dx * Mat::outer_product(weight * grid_v, dpos);  // APIC C
      }
    p.x += dt * p.v;                       // Advection
    if (p.type <= 1) {                     // plastic
      auto F = (Mat(1) + dt * p.C) * p.F;  // MLS-MPM F-update
      if (p.type == 1) {
        Mat svd_u, sig, svd_v;
        svd(F, svd_u, sig, svd_v);
        for (int i = 0; i < 2; i++)  // Snow Plasticity
          sig[i][i] = clamp(sig[i][i], 1.0_f - 2.5e-2_f, 1.0_f + 7.5e-3_f);
        real oldJ = determinant(F);
        F = svd_u * sig * transposed(svd_v);
        real Jp_new = clamp(p.Jp * oldJ / determinant(F), 0.6_f, 20.0_f);
        p.Jp = Jp_new;
      }
      p.F = F;
    } else {  // liquid
      p.Jp *= determinant(Mat(1) + dt * p.C);
    }
  }
}

void add_object(Vec center, int type, int block) {
  auto gen = [&](int k) {
    Vector2 offset(0, 0);
    if (k >= 0)
      offset =
          Vector2(tetris_offsets[block][k][0], tetris_offsets[block][k][1]);
    int colors[] {0xED553B, 0xF2B134, 0x068587};
    for (int i = 0; i < 30 * pow<2>(n / 80.0); i++)
      particles.push_back(
          Particle((Vec::rand() + offset) * 0.05_f + center, colors[type], type));
  };
  gen(-1);
  gen(0);
  gen(1);
  gen(2);
}

int main() {
  GUI gui("Real-time 2D MLS-MPM", window_size, window_size);
  for (int i = 0; i < 7; i++) {
    add_object(Vector2(0.3 + i % 2 * 0.3, 0.2 + i * 0.08), i % 3, i);
  }
  auto &canvas = gui.get_canvas();
  int f = 0;
  for (int i = 0;; i++) {               //              Main Loop
    advance(dt);                        //     Advance simulation
    if (i % int(frame_dt / dt) == 0) {  //        Visualize frame
      canvas.clear(0x112F41);           //       Clear background
      canvas.rect(Vec(0.04), Vec(0.96))
          .radius(2)
          .color(0x4FB99F)
          .close();  // Box
      for (auto p : particles)
        canvas.circle(p.x).radius(2).color(p.c);  // Particles
      gui.update();                               // Update image
      // canvas.img.write_as_image(fmt::format("tmp/{:05d}.png", f++));
    }
  }
}  //----------------------------------------------------------------------------

// g++ tetris.cpp -std=c++14 -g -lX11 -lpthread -O3 -o tetris && ./tetris<|endoftext|>


<commit_before>/*
    This file is part of tgl-library

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Copyright Topology LP 2016
*/

#include "tgl-dc.h"

#include "mtproto-client.h"
#include "queries.h"
#include "tgl-net.h"
#include "tgl-timer.h"

static const float SESSION_CLEANUP_TIMEOUT = 5.0;

void tglq_query_remove(std::shared_ptr<query> q);
bool send_pending_query(std::shared_ptr<query> q) {
    assert(q->DC);
    if (!q->DC->auth_key_id || !q->DC->sessions[0]) {
        TGL_WARNING("not ready to send pending query " << q << ", re-queuing");
        tglmp_dc_create_session(q->DC);
        q->DC->add_pending_query(q);
        return false;
    }

    q->flags &= ~QUERY_ACK_RECEIVED;
    tglq_query_remove(q);
    q->session = q->DC->sessions[0];
    q->msg_id = tglmp_encrypt_send_message (q->session->c, (int*)q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
    tgl_state::instance()->queries_tree.push_back(q);
    q->session_id = q->session->session_id;
    auto dc = q->session->dc.lock();
    if (dc && !(dc->flags & TGLDCF_CONFIGURED) && !(q->flags & QUERY_FORCE_SEND)) {
        q->session_id = 0;
    }

    TGL_DEBUG("Sending pending query \"" << (q->methods->name ? q->methods->name : "") << "\" (" << q->msg_id << ") of size " << 4 * q->data_len << " to DC " << q->DC->id);

    q->ev->start(q->methods->timeout ? q->methods->timeout : DEFAULT_QUERY_TIMEOUT);

    return true;
}

tgl_dc::tgl_dc()
    : session_cleanup_timer(tgl_state::instance()->timer_factory()->create_timer(std::bind(&tgl_dc::cleanup_timer_expired, this)))
{
}

void tgl_dc::send_pending_queries() {
    TGL_NOTICE("sending pending queries for DC " << id);
    while (!pending_queries.empty()) {
        std::shared_ptr<query> q = pending_queries.front();
        pending_queries.pop_front();
        if (!send_pending_query(q)) {
            TGL_ERROR("sending pending query failed for DC " << id);
            break;
        }
    }
}

void tgl_dc::add_query(std::shared_ptr<query> q) {
    active_queries.push_back(q);
    session_cleanup_timer->cancel();
}

void tgl_dc::remove_query(std::shared_ptr<query> q) {
    active_queries.remove(q);

    if (active_queries.empty() && pending_queries.empty() && tgl_state::instance()->DC_working.get() != this) {
        session_cleanup_timer->start(SESSION_CLEANUP_TIMEOUT);
    }
}

void tgl_dc::add_pending_query(std::shared_ptr<query> q) {
    pending_queries.push_back(q);
}

void tgl_dc::remove_pending_query(std::shared_ptr<query> q) {
    pending_queries.remove(q);
}

void tgl_dc::cleanup_timer_expired() {
    if (active_queries.empty() && pending_queries.empty()) {
        TGL_DEBUG("cleanup timer expired for DC " << id << ", deleting sessions");
        for (int i = 0; i < sessions.size(); ++i) {
            std::shared_ptr<tgl_session> session = sessions[i];
            if (session) {
                session->c->close();
                session->ev->cancel();
                session->c = nullptr;
                session->ev = nullptr;
                sessions[i] = nullptr;
            }
        }
    }
}
<commit_msg>Fix build failure on Linux gcc<commit_after>/*
    This file is part of tgl-library

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Copyright Topology LP 2016
*/

#include "tgl-dc.h"

#include "mtproto-client.h"
#include "queries.h"
#include "tgl-net.h"
#include "tgl-timer.h"

static const float SESSION_CLEANUP_TIMEOUT = 5.0;

void tglq_query_remove(std::shared_ptr<query> q);
bool send_pending_query(std::shared_ptr<query> q) {
    assert(q->DC);
    if (!q->DC->auth_key_id || !q->DC->sessions[0]) {
        TGL_WARNING("not ready to send pending query " << q << ", re-queuing");
        tglmp_dc_create_session(q->DC);
        q->DC->add_pending_query(q);
        return false;
    }

    q->flags &= ~QUERY_ACK_RECEIVED;
    tglq_query_remove(q);
    q->session = q->DC->sessions[0];
    q->msg_id = tglmp_encrypt_send_message (q->session->c, (int*)q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
    tgl_state::instance()->queries_tree.push_back(q);
    q->session_id = q->session->session_id;
    auto dc = q->session->dc.lock();
    if (dc && !(dc->flags & TGLDCF_CONFIGURED) && !(q->flags & QUERY_FORCE_SEND)) {
        q->session_id = 0;
    }

    TGL_DEBUG("Sending pending query \"" << (q->methods->name ? q->methods->name : "") << "\" (" << q->msg_id << ") of size " << 4 * q->data_len << " to DC " << q->DC->id);

    q->ev->start(q->methods->timeout ? q->methods->timeout : DEFAULT_QUERY_TIMEOUT);

    return true;
}

tgl_dc::tgl_dc()
    : session_cleanup_timer(tgl_state::instance()->timer_factory()->create_timer(std::bind(&tgl_dc::cleanup_timer_expired, this)))
{
}

void tgl_dc::send_pending_queries() {
    TGL_NOTICE("sending pending queries for DC " << id);
    while (!pending_queries.empty()) {
        std::shared_ptr<query> q = pending_queries.front();
        pending_queries.pop_front();
        if (!send_pending_query(q)) {
            TGL_ERROR("sending pending query failed for DC " << id);
            break;
        }
    }
}

void tgl_dc::add_query(std::shared_ptr<query> q) {
    active_queries.push_back(q);
    session_cleanup_timer->cancel();
}

void tgl_dc::remove_query(std::shared_ptr<query> q) {
    active_queries.remove(q);

    if (active_queries.empty() && pending_queries.empty() && tgl_state::instance()->DC_working.get() != this) {
        session_cleanup_timer->start(SESSION_CLEANUP_TIMEOUT);
    }
}

void tgl_dc::add_pending_query(std::shared_ptr<query> q) {
    pending_queries.push_back(q);
}

void tgl_dc::remove_pending_query(std::shared_ptr<query> q) {
    pending_queries.remove(q);
}

void tgl_dc::cleanup_timer_expired() {
    if (active_queries.empty() && pending_queries.empty()) {
        TGL_DEBUG("cleanup timer expired for DC " << id << ", deleting sessions");
        for (size_t i = 0; i < sessions.size(); ++i) {
            std::shared_ptr<tgl_session> session = sessions[i];
            if (session) {
                session->c->close();
                session->ev->cancel();
                session->c = nullptr;
                session->ev = nullptr;
                sessions[i] = nullptr;
            }
        }
    }
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2012-2013 Tokutek Inc.  All rights reserved."
#ident "$Id$"

#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <assert.h>

#include "source_file.h"
#include "manager.h"
#include "mutex.h"

////////////////////////////////////////////////////////
//
source_file::source_file(const char * const path) : m_full_path(strdup(path)), m_next(NULL), m_reference_count(0)
{
};

source_file::~source_file(void) {
    free(m_full_path);
}

int source_file::init(void)
{
    {
        int r = pthread_mutex_init(&m_mutex, NULL);
        if (r!=0) {
            the_manager.fatal_error(r, "mutex_init at %s:%d", __FILE__, __LINE__);
            return r;
        }
    }
    {
        int r = pthread_cond_init(&m_cond, NULL);
        if (r!=0) {
            the_manager.fatal_error(r, "cond_init at %s:%d", __FILE__, __LINE__);
            ignore(pthread_mutex_destroy(&m_mutex));
            return r;
        }
    }
    {
        int r = pthread_rwlock_init(&m_name_rwlock, NULL);
        if (r!=0) {
            pthread_mutex_destroy(&m_mutex); // don't worry about an error here.
            pthread_cond_destroy(&m_cond); // don't worry about an error here.
            return r;
        }

    }
    return 0;
}

////////////////////////////////////////////////////////
//
const char * source_file::name(void)
{
    return m_full_path;
}

////////////////////////////////////////////////////////
//
source_file * source_file::next(void)
{
    return m_next;
}

////////////////////////////////////////////////////////
//
void source_file::set_next(source_file *next_source) {
    m_next = next_source;
}

static bool ranges_intersect (uint64_t lo0, uint64_t hi0,
                              uint64_t lo1, uint64_t hi1)
// Effect: Return true iff [lo0,hi0)  (the half-open interval from lo0 inclusive to hi0 exclusive) intersects [lo1, hi1).
{
    if (lo0 >= hi0) return false; // range0 is empty
    if (lo1 >= hi1) return false; // range1 is empty
    if (hi0 <= lo1) return false; // range0 is before range1
    if (hi1 <= lo0) return false; // range1 is before range0
    return true;
}

bool source_file::lock_range_would_block_unlocked(uint64_t lo, uint64_t hi) {
    size_t size = m_locked_ranges.size();
    for (size_t i = 0; i<size; i++) {
        if (ranges_intersect(m_locked_ranges[i].lo, m_locked_ranges[i].hi,
                             lo, hi)) {
            return true;
        }
    }
    return false;
}

////////////////////////////////////////////////////////
//
int source_file::lock_range(uint64_t lo, uint64_t hi)
{
    {
        int r = pmutex_lock(&m_mutex);
        if (r!=0) return r;
    }
    while (this->lock_range_would_block_unlocked(lo, hi)) {
        int r = pthread_cond_wait(&m_cond, &m_mutex);
        if (r!=0) {
            the_manager.fatal_error(r, "Trying to cond_wait at %s:%d", __FILE__, __LINE__);
            ignore(pmutex_unlock(&m_mutex));
            return r;
        }
    }
    // Got here, we don't intersect any of the ranges.
    struct range new_range = {lo,hi};
    m_locked_ranges.push_back((struct range)new_range);
    {
        int r = pmutex_unlock(&m_mutex);
        return r;
    }
}

////////////////////////////////////////////////////////
//
int source_file::unlock_range(uint64_t lo, uint64_t hi)
{
    {
        int r = pmutex_lock(&m_mutex);
        if (r!=0) return r;
    }
    size_t size = m_locked_ranges.size();
    for (size_t i=0; i<size; i++) {
        if (m_locked_ranges[i].lo == lo &&
            m_locked_ranges[i].hi == hi) {
            m_locked_ranges[i] = m_locked_ranges[size-1];
            m_locked_ranges.pop_back();
            {
                int r = pthread_cond_broadcast(&m_cond);
                if (r!=0) {
                    the_manager.fatal_error(r, "Trying to cond_broadcast at %s:%d", __FILE__, __LINE__);
                    ignore(pmutex_unlock(&m_mutex));
                    return r;
                }
            }
            {
                int r = pmutex_unlock(&m_mutex);
                if (r!=0) {
                    return r;
                }
            }
            return 0;
        }
    }
    // No such range.
    the_manager.fatal_error(EINVAL, "Range doesn't exist at %s:%d", __FILE__, __LINE__);
    ignore(pmutex_unlock(&m_mutex)); // ignore any error from this since we already have an error.
    return EINVAL;
}

////////////////////////////////////////////////////////
//
int source_file::name_write_lock(void)
{
    int r = pthread_rwlock_wrlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_rwlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::name_read_lock(void)
{
    int r = pthread_rwlock_rdlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_rdlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::name_unlock(void)
{
    int r = pthread_rwlock_unlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_unlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::rename(const char * new_name)
{
    int r = 0;
    free(m_full_path);
    m_full_path = realpath(new_name, NULL);
    if (m_full_path == NULL) {
        r = -1;
    }

    return r;
}

////////////////////////////////////////////////////////
//
void source_file::add_reference(void)
{
    __sync_fetch_and_add(&m_reference_count, 1);
}

////////////////////////////////////////////////////////
//
void source_file::remove_reference(void)
{
    // TODO.  How can the code that decremented a reference count only if it was positive be right?  Under what conditions could someone be decrementing a refcount when they don't know that it's positive?
    assert(m_reference_count>0);
    __sync_fetch_and_add(&m_reference_count, -1);
}

////////////////////////////////////////////////////////
//
unsigned int source_file::get_reference_count(void)
{
    return m_reference_count;
}

// Instantiate the templates we need
template class std::vector<range>;
<commit_msg>Refs #6614.  Formatting.<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2012-2013 Tokutek Inc.  All rights reserved."
#ident "$Id$"

#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <assert.h>

#include "source_file.h"
#include "manager.h"
#include "mutex.h"

////////////////////////////////////////////////////////
//
source_file::source_file(const char * const path) : m_full_path(strdup(path)), m_next(NULL), m_reference_count(0)
{
};

source_file::~source_file(void) {
    free(m_full_path);
}

int source_file::init(void)
{
    {
        int r = pthread_mutex_init(&m_mutex, NULL);
        if (r!=0) {
            the_manager.fatal_error(r, "mutex_init at %s:%d", __FILE__, __LINE__);
            return r;
        }
    }
    {
        int r = pthread_cond_init(&m_cond, NULL);
        if (r!=0) {
            the_manager.fatal_error(r, "cond_init at %s:%d", __FILE__, __LINE__);
            ignore(pthread_mutex_destroy(&m_mutex));
            return r;
        }
    }
    {
        int r = pthread_rwlock_init(&m_name_rwlock, NULL);
        if (r!=0) {
            pthread_mutex_destroy(&m_mutex); // don't worry about an error here.
            pthread_cond_destroy(&m_cond); // don't worry about an error here.
            return r;
        }

    }
    return 0;
}

////////////////////////////////////////////////////////
//
const char * source_file::name(void)
{
    return m_full_path;
}

////////////////////////////////////////////////////////
//
source_file * source_file::next(void)
{
    return m_next;
}

////////////////////////////////////////////////////////
//
void source_file::set_next(source_file *next_source) {
    m_next = next_source;
}

static bool ranges_intersect (uint64_t lo0, uint64_t hi0,
                              uint64_t lo1, uint64_t hi1)
// Effect: Return true iff [lo0,hi0)  (the half-open interval from lo0 inclusive to hi0 exclusive) intersects [lo1, hi1).
{
    if (lo0 >= hi0) return false; // range0 is empty
    if (lo1 >= hi1) return false; // range1 is empty
    if (hi0 <= lo1) return false; // range0 is before range1
    if (hi1 <= lo0) return false; // range1 is before range0
    return true;
}

bool source_file::lock_range_would_block_unlocked(uint64_t lo, uint64_t hi) {
    size_t size = m_locked_ranges.size();
    for (size_t i = 0; i<size; i++) {
        if (ranges_intersect(m_locked_ranges[i].lo, m_locked_ranges[i].hi,
                             lo, hi)) {
            return true;
        }
    }
    return false;
}

////////////////////////////////////////////////////////
//
int source_file::lock_range(uint64_t lo, uint64_t hi)
{
    {
        int r = pmutex_lock(&m_mutex);
        if (r!=0) return r;
    }
    while (this->lock_range_would_block_unlocked(lo, hi)) {
        int r = pthread_cond_wait(&m_cond, &m_mutex);
        if (r!=0) {
            the_manager.fatal_error(r, "Trying to cond_wait at %s:%d", __FILE__, __LINE__);
            ignore(pmutex_unlock(&m_mutex));
            return r;
        }
    }
    // Got here, we don't intersect any of the ranges.
    struct range new_range = {lo,hi};
    m_locked_ranges.push_back((struct range)new_range);
    return pmutex_unlock(&m_mutex);
}

////////////////////////////////////////////////////////
//
int source_file::unlock_range(uint64_t lo, uint64_t hi)
{
    {
        int r = pmutex_lock(&m_mutex);
        if (r!=0) return r;
    }
    size_t size = m_locked_ranges.size();
    for (size_t i=0; i<size; i++) {
        if (m_locked_ranges[i].lo == lo &&
            m_locked_ranges[i].hi == hi) {
            m_locked_ranges[i] = m_locked_ranges[size-1];
            m_locked_ranges.pop_back();
            {
                int r = pthread_cond_broadcast(&m_cond);
                if (r!=0) {
                    the_manager.fatal_error(r, "Trying to cond_broadcast at %s:%d", __FILE__, __LINE__);
                    ignore(pmutex_unlock(&m_mutex));
                    return r;
                }
            }
            {
                int r = pmutex_unlock(&m_mutex);
                if (r!=0) {
                    return r;
                }
            }
            return 0;
        }
    }
    // No such range.
    the_manager.fatal_error(EINVAL, "Range doesn't exist at %s:%d", __FILE__, __LINE__);
    ignore(pmutex_unlock(&m_mutex)); // ignore any error from this since we already have an error.
    return EINVAL;
}

////////////////////////////////////////////////////////
//
int source_file::name_write_lock(void)
{
    int r = pthread_rwlock_wrlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_rwlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::name_read_lock(void)
{
    int r = pthread_rwlock_rdlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_rdlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::name_unlock(void)
{
    int r = pthread_rwlock_unlock(&m_name_rwlock);
    if (r!=0) {
        the_manager.fatal_error(r, "rwlock_unlock at %s:%d", __FILE__, __LINE__);
    }
    return r;
}

////////////////////////////////////////////////////////
//
int source_file::rename(const char * new_name)
{
    int r = 0;
    free(m_full_path);
    m_full_path = realpath(new_name, NULL);
    if (m_full_path == NULL) {
        r = -1;
    }

    return r;
}

////////////////////////////////////////////////////////
//
void source_file::add_reference(void)
{
    __sync_fetch_and_add(&m_reference_count, 1);
}

////////////////////////////////////////////////////////
//
void source_file::remove_reference(void)
{
    // TODO.  How can the code that decremented a reference count only if it was positive be right?  Under what conditions could someone be decrementing a refcount when they don't know that it's positive?
    assert(m_reference_count>0);
    __sync_fetch_and_add(&m_reference_count, -1);
}

////////////////////////////////////////////////////////
//
unsigned int source_file::get_reference_count(void)
{
    return m_reference_count;
}

// Instantiate the templates we need
template class std::vector<range>;
<|endoftext|>