<commit_before>#ifndef _SDD_MEM_CACHE_HH_
#define _SDD_MEM_CACHE_HH_

#include <algorithm> // for_each, nth_element
#include <cstdint>   // uint32_t
#include <forward_list>
#include <iterator>  // distance
#include <numeric>   // accumulate
#include <tuple>
#include <utility>   // forward
#include <vector>

#include "sdd/mem/hash_table.hh"
#include "sdd/mem/interrupt.hh"
#include "sdd/util/hash.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace mem {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Used by cache to know if an operation should be cached or not.
///
/// A filter should always return the same result for the same operation.
template <typename T, typename... Filters>
struct apply_filters;

/// @internal
/// @brief Base case.
///
/// All filters have been applied and they all accepted the operation.
template <typename T>
struct apply_filters<T>
{
  constexpr
  bool
  operator()(const T&)
  const
  {
    return true;
  }
};

/// @internal
/// @brief Recursive case.
///
/// Chain filters calls: as soon as a filter reject an operation, the evaluation is stopped.
template <typename T, typename Filter, typename... Filters>
struct apply_filters<T, Filter, Filters...>
{
  bool
  operator()(const T& op)
  const
  {
    return Filter()(op) ? apply_filters<T, Filters...>()(op) : false;
  }
};

/*------------------------------------------------------------------------------------------------*/

namespace /* anonymous */ {

/// @internal
/// @brief The statistics of a cache.
///
/// A statistic is made of several rounds: each time a cache is cleaned up, a new round is
/// created. Thus, one can have detailed statistics to see how well the cache performed.
struct cache_statistics
{
  /// @internal
  /// @brief Statistic between two cleanups.
  struct round
  {
    round()
      : hits(0)
      , misses(0)
      , filtered(0)
    {}

    /// @brief The number of hits in a round.
    std::size_t hits;

    /// @brief The number of misses in a round.
    std::size_t misses;

    /// @brief The number of filtered entries in a round.
    std::size_t filtered;
  };

  /// @brief The list of all rounds.
  std::forward_list<round> rounds;

  /// @brief Default constructor.
  cache_statistics()
    : rounds(1)
  {}

  /// @brief Get the number of rounds.
  std::size_t
  size()
  const noexcept
  {
    return std::distance(rounds.begin(), rounds.end()); // forward_list lacks a size() function
  }

  /// @brief Get the number of performed cleanups.
  std::size_t
  cleanups()
  const noexcept
  {
    return size() - 1;
  }

  round
  total()
  const noexcept
  {
    return std::accumulate( rounds.begin(), rounds.end(), round()
                          , [&](const round& acc, const round& r) -> round
                               {
                                 round res;
                                 res.hits = acc.hits + r.hits;
                                 res.misses = acc.misses + r.misses;
                                 res.filtered = acc.filtered + r.filtered;
                                 return res;
                               }
                          );
  }
};

} // namespace anonymous

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief  A generic cache.
/// @tparam Operation is the operation type.
/// @tparam EvaluationError is the exception that the evaluation of an Operation can throw.
/// @tparam Filters is a list of filters that reject some operations.
///
/// It uses the LRU strategy to cleanup old entries.
template < typename Context, typename Operation, typename EvaluationError
         , typename... Filters>
class cache
{
  // Can't copy a cache.
  cache(const cache&) = delete;
  cache* operator=(const cache&) = delete;

private:

  /// @brief The type of the context of this cache.
  using context_type = Context;

  /// @brief The type of the result of an operation stored in the cache.
  using result_type = typename Operation::result_type;

  /// @brief Associate an operation to its result into the cache.
  ///
  /// The operation acts as a key and the associated result is the value counterpart.
  struct
#if defined __clang__
  LIBSDD_ATTRIBUTE_PACKED
#endif
  cache_entry
  {
    // Can't copy a cache_entry.
    cache_entry(const cache_entry&) = delete;
    cache_entry& operator=(const cache_entry&) = delete;

    /// @brief
    mem::intrusive_member_hook<cache_entry> hook;

    /// @brief The cached operation.
    const Operation operation;

    /// @brief The result of the evaluation of operation.
    const result_type result;

    /// @brief The last time this entry has been used.
    ///
    /// Used by the LRU cache cleanup strategy.
    std::uint32_t date_;

    std::uint32_t nb_hits_;

    /// brief The 'in use' bit position in nb_hits_.
    static constexpr std::uint32_t in_use_mask = (1u << 31);

    /// @brief Constructor.
    template <typename... Args>
    cache_entry(Operation&& op, Args&&... args)
      : hook()
      , operation(std::move(op))
      , result(std::forward<Args>(args)...)
      , date_(in_use_mask) // initially in use
      , nb_hits_(0)
    {}

    /// @brief Cache entries are only compared using their operations.
    bool
    operator==(const cache_entry& other)
    const noexcept
    {
      return operation == other.operation;
    }

    /// @brief Get the last access date of this entry.
    std::uint32_t
    date()
    const noexcept
    {
      return date_ & ~in_use_mask;
    }

    /// @brief Set this cache entry to a 'never accessed' state.
    void
    reset_date()
    noexcept
    {
      date_ &= in_use_mask;
    }

    /// @brief Increment the number of hits.
    void
    set_date(std::uint32_t last_date)
    noexcept
    {
      date_ = last_date | (date_ & in_use_mask);
    }

    /// @brief Set this cache entry to a 'not in use' state.
    void
    reset_in_use()
    noexcept
    {
      date_ &= ~in_use_mask;
    }

    /// @brief Tell if this cache entry is in an 'in use' state.
    bool
    in_use()
    const noexcept
    {
      return date_ & in_use_mask;
    }

    /// @brief Increment the number of hits.
    void
    increment_nb_hits()
    noexcept
    {
      ++nb_hits_;
    }

    /// @brief Get the number of hits.
    std::uint32_t
    nb_hits()
    const noexcept
    {
      return nb_hits_;
    }
  };

  /// @brief Hash a cache_entry.
  ///
  /// We only use the Operation part of a cache_entry to find it in the cache, in order
  /// to manage the set that stores cache entries as a map.
  struct hash_key
  {
    std::size_t
    operator()(const cache_entry& x)
    const noexcept(noexcept(util::hash(x.operation)))
    {
      return util::hash(x.operation);
    }
  };

  /// @brief This cache's context.
  context_type& cxt_;

  /// @brief The cache name.
  const std::string name_;

  /// @brief The wanted load factor.
  double max_load_factor_;

  /// @brief An intrusive hash table.
  using set_type = mem::hash_table<cache_entry, hash_key>;

  /// @brief The actual storage of caches entries.
  set_type set_;

  /// @brief The maximum size this cache is authorized to grow to.
  std::size_t max_size_;

  /// @brief The statistics of this cache.
  cache_statistics stats_;

  /// @brief The date of last access.
  std::uint32_t date_;

public:

  /// @brief Construct a cache.
  /// @param context This cache's context.
  /// @param name Give a name to this cache.
  /// @param size tells how many cache entries are keeped in the cache.
  ///
  /// When the maximal size is reached, a cleanup is launched: half of the cache is removed,
  /// using a LRU strategy. This cache will never perform a rehash, therefore it allocates
  /// all the memory it needs at its construction.
  cache(context_type& context, const std::string& name, std::size_t size)
    : cxt_(context)
    , name_(name)
    , max_load_factor_(0.9)
    , set_(size)
    , max_size_(set_.bucket_count())
    , stats_()
    , date_(0)
  {}

  /// @brief Destructor.
  ~cache()
  {
    clear();
  }

  /// @brief Cache lookup.
  result_type
  operator()(Operation&& op)
  {
    // Check if the current operation should not be cached.
    if (not apply_filters<Operation, Filters...>()(op))
    {
      ++stats_.rounds.front().filtered;
      try
      {
        return op(cxt_);
      }
      catch (EvaluationError& e)
      {
        --stats_.rounds.front().filtered;
        e.add_step(std::move(op));
        throw;
      }
    }

    // Lookup for op.
    typename set_type::insert_commit_data commit_data;
    auto insertion = set_.insert_check( op
                                      , std::hash<Operation>()
                                      , [](const Operation& lhs, const cache_entry& rhs)
                                          {return lhs == rhs.operation;}
                                      , commit_data);

    // Check if op has already been computed.
    if (not insertion.second)
    {
      ++stats_.rounds.front().hits;
      insertion.first->set_date(++date_);
      insertion.first->increment_nb_hits();
      return insertion.first->result;
    }

    ++stats_.rounds.front().misses;

    // Clean up the cache, if necessary.
    cleanup();

    cache_entry* entry;
    try
    {
      entry = new cache_entry(std::move(op), op(cxt_));
    }
    catch (EvaluationError& e)
    {
      --stats_.rounds.front().misses;
      e.add_step(std::move(op));
      throw;
    }
    catch (interrupt<result_type>&)
    {
      --stats_.rounds.front().misses;
      throw;
    }
    // A cache entry is constructed with the 'in use' bit set.
    entry->reset_in_use();
    set_.insert_commit(*entry, commit_data); // doesn't throw
    return entry->result;
  }

  /// @brief The load factor of the underlying hash table.
  double
  load_factor()
  const noexcept
  {
    return static_cast<double>(set_.size()) / static_cast<double>(max_size_);
  }

  /// @brief Remove half of the cache (LRU strategy).
  void
  cleanup()
  {
    if (load_factor() < max_load_factor_)
    {
      return;
    }

    stats_.rounds.emplace_front(cache_statistics::round());

    std::vector<cache_entry*> vec;
    vec.reserve(set_.size());
    for (auto& e : set_)
    {
      if (not e.in_use())
      {
        vec.push_back(&e);
      }
    }

    // Compute the number of elements to keep in order to reduce the load factor by a factor of 2.
    const std::size_t to_keep = static_cast<std::size_t>(max_size_ * max_load_factor_/2);
    const std::size_t cut_point = vec.size() - to_keep;

    // All entries after the entry at cut_point are more recent and more frequently used.
    std::nth_element( vec.begin(), vec.begin() + cut_point, vec.end()
                    , [](cache_entry* lhs, cache_entry* rhs)
                        {
                          if (lhs->date() < rhs->date())
                          {
                            return true;
                          }
                          else if (lhs->date() == rhs->date())
                          {
                            return lhs->nb_hits() < rhs->nb_hits();
                          }
                          return false;
                        });

    // Delete all cache entries with a number of entries smaller than the median.
    std::for_each( vec.begin(), vec.begin() + cut_point
                 , [&](cache_entry* e)
                      {
                        const auto cit = set_.find(*e);
                        assert(cit != set_.end());
                        set_.erase(cit);
                        delete e;
                      });

    // Reset the number of hits of all remaining cache entries.
    std::for_each(vec.begin() + cut_point, vec.end(), [](cache_entry* e){e->reset_date();});

    // Reset the global date.
    date_ = 0;
  }

  /// @brief Remove all entries of the cache.
  void
  clear()
  noexcept
  {
    set_.clear_and_dispose([](cache_entry* x){delete x;});
  }

  /// @brief Get the number of cached operations.
  std::size_t
  size()
  const noexcept
  {
    return set_.size();
  }

  /// @brief Get the statistics of this cache.
  const cache_statistics&
  statistics()
  const noexcept
  {
    return stats_;
  }

  /// @brief Get this cache's name
  const std::string&
  name()
  const noexcept
  {
    return name_;
  }
};

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::mem

#endif // _SDD_MEM_CACHE_HH_
<commit_msg>Handle some cache cleanup corner-cases.<commit_after>#ifndef _SDD_MEM_CACHE_HH_
#define _SDD_MEM_CACHE_HH_

#include <algorithm> // for_each, nth_element
#include <cstdint>   // uint32_t
#include <forward_list>
#include <iterator>  // distance
#include <numeric>   // accumulate
#include <tuple>
#include <utility>   // forward
#include <vector>

#include "sdd/mem/hash_table.hh"
#include "sdd/mem/interrupt.hh"
#include "sdd/util/hash.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace mem {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Used by cache to know if an operation should be cached or not.
///
/// A filter should always return the same result for the same operation.
template <typename T, typename... Filters>
struct apply_filters;

/// @internal
/// @brief Base case.
///
/// All filters have been applied and they all accepted the operation.
template <typename T>
struct apply_filters<T>
{
  constexpr
  bool
  operator()(const T&)
  const
  {
    return true;
  }
};

/// @internal
/// @brief Recursive case.
///
/// Chain filters calls: as soon as a filter reject an operation, the evaluation is stopped.
template <typename T, typename Filter, typename... Filters>
struct apply_filters<T, Filter, Filters...>
{
  bool
  operator()(const T& op)
  const
  {
    return Filter()(op) ? apply_filters<T, Filters...>()(op) : false;
  }
};

/*------------------------------------------------------------------------------------------------*/

namespace /* anonymous */ {

/// @internal
/// @brief The statistics of a cache.
///
/// A statistic is made of several rounds: each time a cache is cleaned up, a new round is
/// created. Thus, one can have detailed statistics to see how well the cache performed.
struct cache_statistics
{
  /// @internal
  /// @brief Statistic between two cleanups.
  struct round
  {
    round()
      : hits(0)
      , misses(0)
      , filtered(0)
    {}

    /// @brief The number of hits in a round.
    std::size_t hits;

    /// @brief The number of misses in a round.
    std::size_t misses;

    /// @brief The number of filtered entries in a round.
    std::size_t filtered;
  };

  /// @brief The list of all rounds.
  std::forward_list<round> rounds;

  /// @brief Default constructor.
  cache_statistics()
    : rounds(1)
  {}

  /// @brief Get the number of rounds.
  std::size_t
  size()
  const noexcept
  {
    return std::distance(rounds.begin(), rounds.end()); // forward_list lacks a size() function
  }

  /// @brief Get the number of performed cleanups.
  std::size_t
  cleanups()
  const noexcept
  {
    return size() - 1;
  }

  round
  total()
  const noexcept
  {
    return std::accumulate( rounds.begin(), rounds.end(), round()
                          , [&](const round& acc, const round& r) -> round
                               {
                                 round res;
                                 res.hits = acc.hits + r.hits;
                                 res.misses = acc.misses + r.misses;
                                 res.filtered = acc.filtered + r.filtered;
                                 return res;
                               }
                          );
  }
};

} // namespace anonymous

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief  A generic cache.
/// @tparam Operation is the operation type.
/// @tparam EvaluationError is the exception that the evaluation of an Operation can throw.
/// @tparam Filters is a list of filters that reject some operations.
///
/// It uses the LRU strategy to cleanup old entries.
template < typename Context, typename Operation, typename EvaluationError
         , typename... Filters>
class cache
{
  // Can't copy a cache.
  cache(const cache&) = delete;
  cache* operator=(const cache&) = delete;

private:

  /// @brief The type of the context of this cache.
  using context_type = Context;

  /// @brief The type of the result of an operation stored in the cache.
  using result_type = typename Operation::result_type;

  /// @brief Associate an operation to its result into the cache.
  ///
  /// The operation acts as a key and the associated result is the value counterpart.
  struct
#if defined __clang__
  LIBSDD_ATTRIBUTE_PACKED
#endif
  cache_entry
  {
    // Can't copy a cache_entry.
    cache_entry(const cache_entry&) = delete;
    cache_entry& operator=(const cache_entry&) = delete;

    /// @brief
    mem::intrusive_member_hook<cache_entry> hook;

    /// @brief The cached operation.
    const Operation operation;

    /// @brief The result of the evaluation of operation.
    const result_type result;

    /// @brief The last time this entry has been used.
    ///
    /// Used by the LRU cache cleanup strategy.
    std::uint32_t date_;

    std::uint32_t nb_hits_;

    /// brief The 'in use' bit position in nb_hits_.
    static constexpr std::uint32_t in_use_mask = (1u << 31);

    /// @brief Constructor.
    template <typename... Args>
    cache_entry(Operation&& op, Args&&... args)
      : hook()
      , operation(std::move(op))
      , result(std::forward<Args>(args)...)
      , date_(in_use_mask) // initially in use
      , nb_hits_(0)
    {}

    /// @brief Cache entries are only compared using their operations.
    bool
    operator==(const cache_entry& other)
    const noexcept
    {
      return operation == other.operation;
    }

    /// @brief Get the last access date of this entry.
    std::uint32_t
    date()
    const noexcept
    {
      return date_ & ~in_use_mask;
    }

    /// @brief Set this cache entry to a 'never accessed' state.
    void
    reset_date()
    noexcept
    {
      date_ &= in_use_mask;
    }

    /// @brief Increment the number of hits.
    void
    set_date(std::uint32_t last_date)
    noexcept
    {
      date_ = last_date | (date_ & in_use_mask);
    }

    /// @brief Set this cache entry to a 'not in use' state.
    void
    reset_in_use()
    noexcept
    {
      date_ &= ~in_use_mask;
    }

    /// @brief Tell if this cache entry is in an 'in use' state.
    bool
    in_use()
    const noexcept
    {
      return date_ & in_use_mask;
    }

    /// @brief Increment the number of hits.
    void
    increment_nb_hits()
    noexcept
    {
      ++nb_hits_;
    }

    /// @brief Get the number of hits.
    std::uint32_t
    nb_hits()
    const noexcept
    {
      return nb_hits_;
    }
  };

  /// @brief Hash a cache_entry.
  ///
  /// We only use the Operation part of a cache_entry to find it in the cache, in order
  /// to manage the set that stores cache entries as a map.
  struct hash_key
  {
    std::size_t
    operator()(const cache_entry& x)
    const noexcept(noexcept(util::hash(x.operation)))
    {
      return util::hash(x.operation);
    }
  };

  /// @brief This cache's context.
  context_type& cxt_;

  /// @brief The cache name.
  const std::string name_;

  /// @brief The wanted load factor for the underlying hash table.
  static constexpr double max_load_factor = 0.85;

  /// @brief An intrusive hash table.
  using set_type = mem::hash_table<cache_entry, hash_key>;

  /// @brief The actual storage of caches entries.
  set_type set_;

  /// @brief The maximum size this cache is authorized to grow to.
  std::size_t max_size_;

  /// @brief The statistics of this cache.
  cache_statistics stats_;

  /// @brief The date of last access.
  std::uint32_t date_;

public:

  /// @brief Construct a cache.
  /// @param context This cache's context.
  /// @param name Give a name to this cache.
  /// @param size tells how many cache entries are keeped in the cache.
  ///
  /// When the maximal size is reached, a cleanup is launched: half of the cache is removed,
  /// using a LRU strategy. This cache will never perform a rehash, therefore it allocates
  /// all the memory it needs at its construction.
  cache(context_type& context, const std::string& name, std::size_t size)
    : cxt_(context)
    , name_(name)
    , set_(size, max_load_factor, true /* no rehash */)
    , max_size_(set_.bucket_count() * max_load_factor)
    , stats_()
    , date_(0)
  {}

  /// @brief Destructor.
  ~cache()
  {
    clear();
  }

  /// @brief Cache lookup.
  result_type
  operator()(Operation&& op)
  {
    // Check if the current operation should not be cached.
    if (not apply_filters<Operation, Filters...>()(op))
    {
      ++stats_.rounds.front().filtered;
      try
      {
        return op(cxt_);
      }
      catch (EvaluationError& e)
      {
        --stats_.rounds.front().filtered;
        e.add_step(std::move(op));
        throw;
      }
    }

    // Lookup for op.
    typename set_type::insert_commit_data commit_data;
    auto insertion = set_.insert_check( op
                                      , std::hash<Operation>()
                                      , [](const Operation& lhs, const cache_entry& rhs)
                                          {return lhs == rhs.operation;}
                                      , commit_data);

    // Check if op has already been computed.
    if (not insertion.second)
    {
      ++stats_.rounds.front().hits;
      insertion.first->set_date(++date_);
      insertion.first->increment_nb_hits();
      return insertion.first->result;
    }

    ++stats_.rounds.front().misses;

    cache_entry* entry;
    try
    {
      entry = new cache_entry(std::move(op), op(cxt_));
    }
    catch (EvaluationError& e)
    {
      --stats_.rounds.front().misses;
      e.add_step(std::move(op));
      throw;
    }
    catch (interrupt<result_type>&)
    {
      --stats_.rounds.front().misses;
      throw;
    }

    // Clean up the cache, if necessary.
    cleanup();

    // A cache entry is constructed with the 'in use' bit set.
    entry->reset_in_use();
    set_.insert_commit(*entry, commit_data); // doesn't throw

    return entry->result;
  }

  /// @brief Remove half of the cache.
  void
  cleanup()
  {
    if (set_.size() < max_size_)
    {
      return;
    }

    stats_.rounds.emplace_front(cache_statistics::round());

    std::vector<cache_entry*> vec;
    vec.reserve(set_.size());
    for (auto& e : set_)
    {
      if (not e.in_use())
      {
        vec.push_back(&e);
      }
    }

    if (vec.empty())
    {
      // Can't clean the cache for now, all entries are in use.
      return;
    }
    else if (vec.size() < max_size_ / 2)
    {
      // Not enough entries are not in use to divide the size of the cache by 2.
      // Delete all cache entries which are not in use.
      std::for_each( vec.begin(), vec.end()
                   , [&](cache_entry* e)
                     {
                       const auto cit = set_.find(*e);
                       assert(cit != set_.end());
                       set_.erase(cit);
                       delete e;
                     });
    }
    else // vec.size() >= max_size / 2
    {
      const std::size_t to_keep = static_cast<std::size_t>(max_size_ / 2);
      const std::size_t cut_point = vec.size() - to_keep;

      // All entries after the entry at cut_point are more recent and more frequently used.
      std::nth_element( vec.begin(), vec.begin() + cut_point, vec.end()
                      , [](cache_entry* lhs, cache_entry* rhs)
                          {
                            if (lhs->date() < rhs->date())
                            {
                              return true;
                            }
                            else if (lhs->date() == rhs->date())
                            {
                              return lhs->nb_hits() < rhs->nb_hits();
                            }
                            return false;
                          });

      // Delete all cache entries with a number of entries smaller than the median.
      std::for_each( vec.begin(), vec.begin() + cut_point
                    , [&](cache_entry* e)
                    {
                      const auto cit = set_.find(*e);
                      assert(cit != set_.end());
                      set_.erase(cit);
                      delete e;
                    });
    }
    // Reset the date of all remaining cache entries.
    std::for_each(set_.begin(), set_.end(), [](cache_entry& e){e.reset_date();});
    // Reset the global date.
    date_ = 0;
  }

  /// @brief Remove all entries of the cache.
  void
  clear()
  noexcept
  {
    set_.clear_and_dispose([](cache_entry* x){delete x;});
  }

  /// @brief Get the number of cached operations.
  std::size_t
  size()
  const noexcept
  {
    return set_.size();
  }

  /// @brief Get the statistics of this cache.
  const cache_statistics&
  statistics()
  const noexcept
  {
    return stats_;
  }

  /// @brief Get this cache's name
  const std::string&
  name()
  const noexcept
  {
    return name_;
  }
};

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::mem

#endif // _SDD_MEM_CACHE_HH_
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blockfilter.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
#include <miner.h>
#include <pow.h>
#include <test/test_bitcoin.h>
#include <script/standard.h>
#include <validation.h>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)

static bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index,
                          BlockFilter& filter)
{
    CBlock block;
    if (!ReadBlockFromDisk(block, block_index->GetBlockPos(), Params().GetConsensus())) {
        return false;
    }

    CBlockUndo block_undo;
    if (block_index->nHeight > 0 && !UndoReadFromDisk(block_undo, block_index)) {
        return false;
    }

    filter = BlockFilter(filter_type, block, block_undo);
    return true;
}

static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,
                               uint256& last_header)
{
    BlockFilter expected_filter;
    if (!ComputeFilter(filter_index.GetFilterType(), block_index, expected_filter)) {
        BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
        return false;
    }

    BlockFilter filter;
    uint256 filter_header;
    std::vector<BlockFilter> filters;
    std::vector<uint256> filter_hashes;

    BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
    BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
    BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
    BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
                                                   filter_hashes));

    BOOST_CHECK_EQUAL(filters.size(), 1);
    BOOST_CHECK_EQUAL(filter_hashes.size(), 1);

    BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
    BOOST_CHECK_EQUAL(filter_header, expected_filter.ComputeHeader(last_header));
    BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
    BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());

    filters.clear();
    filter_hashes.clear();
    last_header = filter_header;
    return true;
}

static CBlock CreateBlock(const CBlockIndex* prev,
                          const std::vector<CMutableTransaction>& txns,
                          const CScript& scriptPubKey)
{
    const CChainParams& chainparams = Params();
    std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
    CBlock& block = pblocktemplate->block;
    block.hashPrevBlock = prev->GetBlockHash();
    block.nTime = prev->nTime + 1;

    // Replace mempool-selected txns with just coinbase plus passed-in txns:
    block.vtx.resize(1);
    for (const CMutableTransaction& tx : txns) {
        block.vtx.push_back(MakeTransactionRef(tx));
    }
    // IncrementExtraNonce creates a valid coinbase and merkleRoot
    unsigned int extraNonce = 0;
    IncrementExtraNonce(&block, prev, extraNonce);

    while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;

    return block;
}

static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key,
                       size_t length, std::vector<std::shared_ptr<CBlock>>& chain)
{
    std::vector<CMutableTransaction> no_txns;

    chain.resize(length);
    for (auto& block : chain) {
        block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
        CBlockHeader header = block->GetBlockHeader();

        CValidationState state;
        if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
            return false;
        }
    }

    return true;
}

BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
{
    BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);

    uint256 last_header;

    // Filter should not be found in the index before it is started.
    {
        LOCK(cs_main);

        BlockFilter filter;
        uint256 filter_header;
        std::vector<BlockFilter> filters;
        std::vector<uint256> filter_hashes;

        for (const CBlockIndex* block_index = chainActive.Genesis();
             block_index != nullptr;
             block_index = chainActive.Next(block_index)) {
            BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
            BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header));
            BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
            BOOST_CHECK(!filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
                                                            filter_hashes));
        }
    }

    // BlockUntilSyncedToCurrentChain should return false before index is started.
    BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());

    filter_index.Start();

    // Allow filter index to catch up with the block index.
    constexpr int64_t timeout_ms = 10 * 1000;
    int64_t time_start = GetTimeMillis();
    while (!filter_index.BlockUntilSyncedToCurrentChain()) {
        BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
        MilliSleep(100);
    }

    // Check that filter index has all blocks that were in the chain before it started.
    {
        LOCK(cs_main);
        const CBlockIndex* block_index;
        for (block_index = chainActive.Genesis();
             block_index != nullptr;
             block_index = chainActive.Next(block_index)) {
            CheckFilterLookups(filter_index, block_index, last_header);
        }
    }

    // Create two forks.
    const CBlockIndex* tip;
    {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
    std::vector<std::shared_ptr<CBlock>> chainA, chainB;
    BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA));
    BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB));

    // Check that new blocks on chain A get indexed.
    uint256 chainA_last_header = last_header;
    for (size_t i = 0; i < 2; i++) {
        const auto& block = chainA[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));

        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainA_last_header);
    }

    // Reorg to chain B.
    uint256 chainB_last_header = last_header;
    for (size_t i = 0; i < 3; i++) {
        const auto& block = chainB[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));

        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainB_last_header);
    }

    // Check that filters for stale blocks on A can be retrieved.
    chainA_last_header = last_header;
    for (size_t i = 0; i < 2; i++) {
        const auto& block = chainA[i];
        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainA_last_header);
    }

    // Reorg back to chain A.
     for (size_t i = 2; i < 4; i++) {
         const auto& block = chainA[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));
     }

     // Check that chain A and B blocks can be retrieved.
     chainA_last_header = last_header;
     chainB_last_header = last_header;
     for (size_t i = 0; i < 3; i++) {
         const CBlockIndex* block_index;

         {
             LOCK(cs_main);
             block_index = LookupBlockIndex(chainA[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainA_last_header);

         {
             LOCK(cs_main);
             block_index = LookupBlockIndex(chainB[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainB_last_header);
     }

    // Test lookups for a range of filters/hashes.
    std::vector<BlockFilter> filters;
    std::vector<uint256> filter_hashes;

    {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
    BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));

    BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1);
    BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1);

    filters.clear();
    filter_hashes.clear();

    filter_index.Interrupt();
    filter_index.Stop();
}

BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
{
    SetDataDir("tempdir");

    BlockFilterIndex* filter_index;

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);

    BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index != nullptr);
    BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);

    // Initialize returns false if index already exists.
    BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    int iter_count = 0;
    ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
    BOOST_CHECK_EQUAL(iter_count, 1);

    BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));

    // Destroy returns false because index was already destroyed.
    BOOST_CHECK(!DestroyBlockFilterIndex(BlockFilterType::BASIC));

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);

    // Reinitialize index.
    BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    DestroyAllBlockFilterIndexes();

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: fix outdate include in blockfilter_index_tests<commit_after>// Copyright (c) 2017-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blockfilter.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
#include <miner.h>
#include <pow.h>
#include <test/setup_common.h>
#include <script/standard.h>
#include <validation.h>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)

static bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index,
                          BlockFilter& filter)
{
    CBlock block;
    if (!ReadBlockFromDisk(block, block_index->GetBlockPos(), Params().GetConsensus())) {
        return false;
    }

    CBlockUndo block_undo;
    if (block_index->nHeight > 0 && !UndoReadFromDisk(block_undo, block_index)) {
        return false;
    }

    filter = BlockFilter(filter_type, block, block_undo);
    return true;
}

static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,
                               uint256& last_header)
{
    BlockFilter expected_filter;
    if (!ComputeFilter(filter_index.GetFilterType(), block_index, expected_filter)) {
        BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
        return false;
    }

    BlockFilter filter;
    uint256 filter_header;
    std::vector<BlockFilter> filters;
    std::vector<uint256> filter_hashes;

    BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
    BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
    BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
    BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
                                                   filter_hashes));

    BOOST_CHECK_EQUAL(filters.size(), 1);
    BOOST_CHECK_EQUAL(filter_hashes.size(), 1);

    BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
    BOOST_CHECK_EQUAL(filter_header, expected_filter.ComputeHeader(last_header));
    BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
    BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());

    filters.clear();
    filter_hashes.clear();
    last_header = filter_header;
    return true;
}

static CBlock CreateBlock(const CBlockIndex* prev,
                          const std::vector<CMutableTransaction>& txns,
                          const CScript& scriptPubKey)
{
    const CChainParams& chainparams = Params();
    std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
    CBlock& block = pblocktemplate->block;
    block.hashPrevBlock = prev->GetBlockHash();
    block.nTime = prev->nTime + 1;

    // Replace mempool-selected txns with just coinbase plus passed-in txns:
    block.vtx.resize(1);
    for (const CMutableTransaction& tx : txns) {
        block.vtx.push_back(MakeTransactionRef(tx));
    }
    // IncrementExtraNonce creates a valid coinbase and merkleRoot
    unsigned int extraNonce = 0;
    IncrementExtraNonce(&block, prev, extraNonce);

    while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;

    return block;
}

static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key,
                       size_t length, std::vector<std::shared_ptr<CBlock>>& chain)
{
    std::vector<CMutableTransaction> no_txns;

    chain.resize(length);
    for (auto& block : chain) {
        block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
        CBlockHeader header = block->GetBlockHeader();

        CValidationState state;
        if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
            return false;
        }
    }

    return true;
}

BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
{
    BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);

    uint256 last_header;

    // Filter should not be found in the index before it is started.
    {
        LOCK(cs_main);

        BlockFilter filter;
        uint256 filter_header;
        std::vector<BlockFilter> filters;
        std::vector<uint256> filter_hashes;

        for (const CBlockIndex* block_index = chainActive.Genesis();
             block_index != nullptr;
             block_index = chainActive.Next(block_index)) {
            BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
            BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header));
            BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
            BOOST_CHECK(!filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
                                                            filter_hashes));
        }
    }

    // BlockUntilSyncedToCurrentChain should return false before index is started.
    BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());

    filter_index.Start();

    // Allow filter index to catch up with the block index.
    constexpr int64_t timeout_ms = 10 * 1000;
    int64_t time_start = GetTimeMillis();
    while (!filter_index.BlockUntilSyncedToCurrentChain()) {
        BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
        MilliSleep(100);
    }

    // Check that filter index has all blocks that were in the chain before it started.
    {
        LOCK(cs_main);
        const CBlockIndex* block_index;
        for (block_index = chainActive.Genesis();
             block_index != nullptr;
             block_index = chainActive.Next(block_index)) {
            CheckFilterLookups(filter_index, block_index, last_header);
        }
    }

    // Create two forks.
    const CBlockIndex* tip;
    {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
    std::vector<std::shared_ptr<CBlock>> chainA, chainB;
    BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA));
    BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB));

    // Check that new blocks on chain A get indexed.
    uint256 chainA_last_header = last_header;
    for (size_t i = 0; i < 2; i++) {
        const auto& block = chainA[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));

        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainA_last_header);
    }

    // Reorg to chain B.
    uint256 chainB_last_header = last_header;
    for (size_t i = 0; i < 3; i++) {
        const auto& block = chainB[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));

        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainB_last_header);
    }

    // Check that filters for stale blocks on A can be retrieved.
    chainA_last_header = last_header;
    for (size_t i = 0; i < 2; i++) {
        const auto& block = chainA[i];
        const CBlockIndex* block_index;
        {
            LOCK(cs_main);
            block_index = LookupBlockIndex(block->GetHash());
        }

        BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
        CheckFilterLookups(filter_index, block_index, chainA_last_header);
    }

    // Reorg back to chain A.
     for (size_t i = 2; i < 4; i++) {
         const auto& block = chainA[i];
        BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));
     }

     // Check that chain A and B blocks can be retrieved.
     chainA_last_header = last_header;
     chainB_last_header = last_header;
     for (size_t i = 0; i < 3; i++) {
         const CBlockIndex* block_index;

         {
             LOCK(cs_main);
             block_index = LookupBlockIndex(chainA[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainA_last_header);

         {
             LOCK(cs_main);
             block_index = LookupBlockIndex(chainB[i]->GetHash());
         }
         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
         CheckFilterLookups(filter_index, block_index, chainB_last_header);
     }

    // Test lookups for a range of filters/hashes.
    std::vector<BlockFilter> filters;
    std::vector<uint256> filter_hashes;

    {
        LOCK(cs_main);
        tip = chainActive.Tip();
    }
    BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
    BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));

    BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1);
    BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1);

    filters.clear();
    filter_hashes.clear();

    filter_index.Interrupt();
    filter_index.Stop();
}

BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
{
    SetDataDir("tempdir");

    BlockFilterIndex* filter_index;

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);

    BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index != nullptr);
    BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);

    // Initialize returns false if index already exists.
    BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    int iter_count = 0;
    ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
    BOOST_CHECK_EQUAL(iter_count, 1);

    BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));

    // Destroy returns false because index was already destroyed.
    BOOST_CHECK(!DestroyBlockFilterIndex(BlockFilterType::BASIC));

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);

    // Reinitialize index.
    BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));

    DestroyAllBlockFilterIndexes();

    filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
    BOOST_CHECK(filter_index == nullptr);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <boost/pool/object_pool.hpp>
#include <boost/optional.hpp>
#include "../incl/search.hpp"
#include "../structs/htable.hpp"
#include "../search/openlist.hpp"

template <class D, class Cost> struct Node {
	typename D::PackedState state;
	typename D::Oper pop;
	Cost g, f;
	HtableEntry<Node> closedent;
	Node *parent;
	int openind;

	Node(void) : openind(-1) {}

	static bool pred(Node *a, Node *b) {
		if (a->f == b->f)
			return a->g > b->g;
		return a->f < b->f;
	}

	static void setind(Node *n, int i) { n->openind = i; }
	static int getind(Node *n) { return n->openind; }
};

template <class D> struct Node <D, char> {
	typename D::PackedState state;
	typename D::Oper pop;
	typename D::Cost g, f;
	HtableEntry<Node> closedent;
	IntpqEntry<Node> openent;
	Node *parent;

	static typename D::Cost prio(Node *n) { return n->f; }
	static IntpqEntry<Node> &openentry(Node *n) { return n->openent; }
};

template <class D> struct Node <D, short> : public Node <D, char> {};
template <class D> struct Node <D, int> : public Node <D, char> {};
template <class D> struct Node <D, long> : public Node <D, char> {};

template <class D> class Astar : public Search<D> {
public:

	Result<D> search(D &d, typename D::State &s0) {
		res = Result<D>(true);

		Node<D, Cost> *n0 = init(d, s0);
		closed.add(n0);
		open.push(n0);

		while (!open.empty()) {
			Node<D, Cost> *n = open.pop();
			State buf, &state = d.unpack(buf, n->state);

			if (d.isgoal(state)) {
				handlesol(d, n);
				break;
			}

			if (expand(d, n, state))
				break;
		}

		res.finish();

		closed.prstats(stdout, "closed ");
		dfpair(stdout, "open list type", "%s", open.kind());
		dfpair(stdout, "node size", "%u", sizeof(Node<D, Cost>));

		return res;
	}

	Astar(void) : closed(30000001) {}

private:

	typedef typename D::State State;
	typedef typename D::PackedState PackedState;
	typedef typename D::Undo Undo;
	typedef typename D::Cost Cost;
	typedef typename D::Oper Oper;

	bool expand(D &d, Node<D, Cost> *n, State &state) {
		res.expd++;

		for (unsigned int i = 0; i < d.nops(state); i++) {
			Oper op = d.nthop(state, i);
			if (op == n->pop)
				continue;
			Node<D, Cost> *k = kid(d, n, state, op);
			res.gend++;

			considerkid(d, k);
		}

		return false;
	}

	void considerkid(D &d, Node<D, Cost> *k) {
		unsigned long h = k->state.hash();
		Node<D, Cost> *dup = closed.find(k->state, h);
		if (dup) {
			res.dups++;
			if (k->g >= dup->g) {
				nodes.destroy(k);
				return;
			}
			if (!open.mem(dup))
				open.pre_update(dup);

			dup->f = dup->f - dup->g + k->g;
			dup->g = k->g;
			dup->pop = k->pop;
			dup->parent = k->parent;

			if (!open.mem(dup))
				open.push(dup);
			else
				open.post_update(dup);
			nodes.destroy(k);
		} else {
			closed.add(k, h);
			open.push(k);
		}
	}

	Node<D, Cost> *kid(D &d, Node<D, Cost> *pnode, State &pstate, Oper op) {
		Node<D, Cost> *kid = nodes.construct();
		State buf, &kidst = d.applyinto(kid->state, buf, pstate, op);
		kid->g = pnode->g + d.opcost(pstate, op);
		kid->f = kid->g + d.h(kidst);
		kid->pop = d.revop(pstate, op);
		kid->parent = pnode;
		return kid;
	}

	Node<D, Cost> *init(D &d, State &s0) {
		Node<D, Cost> *n0 = nodes.construct();
		d.pack(n0->state, s0);
		n0->g = 0;
		n0->f = d.h(s0);
		n0->pop = D::Nop;
		n0->parent = NULL;
		return n0;
	}

	void handlesol(D &d, Node<D, Cost> *n) {
		res.cost = n->g;

		for ( ; n; n = n->parent) {
			State buf;
			State &state = d.unpack(buf, n->state);
			res.path.push_back(state);
		}
	}

	struct Closedops {
		static PackedState &key(Node<D, Cost> *n) { return n->state; }
		static unsigned long hash(PackedState &s) { return s.hash(); }
		static bool eq(PackedState &a, PackedState &b) { return a.eq(b); }
		static HtableEntry< Node<D, Cost> > &entry(Node<D, Cost> *n) {
			return n->closedent;
		}
	};

	Result<D> res;
	OpenList< Node<D, Cost>, Node<D, Cost>, Cost > open;
 	Htable< Closedops, PackedState&, Node<D, Cost> > closed;
	boost::object_pool< Node<D, Cost> > nodes;
};<commit_msg>Expand doesn't do the goal test.<commit_after>#include <boost/pool/object_pool.hpp>
#include <boost/optional.hpp>
#include "../incl/search.hpp"
#include "../structs/htable.hpp"
#include "../search/openlist.hpp"

template <class D, class Cost> struct Node {
	typename D::PackedState state;
	typename D::Oper pop;
	Cost g, f;
	HtableEntry<Node> closedent;
	Node *parent;
	int openind;

	Node(void) : openind(-1) {}

	static bool pred(Node *a, Node *b) {
		if (a->f == b->f)
			return a->g > b->g;
		return a->f < b->f;
	}

	static void setind(Node *n, int i) { n->openind = i; }
	static int getind(Node *n) { return n->openind; }
};

template <class D> struct Node <D, char> {
	typename D::PackedState state;
	typename D::Oper pop;
	typename D::Cost g, f;
	HtableEntry<Node> closedent;
	IntpqEntry<Node> openent;
	Node *parent;

	static typename D::Cost prio(Node *n) { return n->f; }
	static IntpqEntry<Node> &openentry(Node *n) { return n->openent; }
};

template <class D> struct Node <D, short> : public Node <D, char> {};
template <class D> struct Node <D, int> : public Node <D, char> {};
template <class D> struct Node <D, long> : public Node <D, char> {};

template <class D> class Astar : public Search<D> {
public:

	Result<D> search(D &d, typename D::State &s0) {
		res = Result<D>(true);

		Node<D, Cost> *n0 = init(d, s0);
		closed.add(n0);
		open.push(n0);

		while (!open.empty()) {
			Node<D, Cost> *n = open.pop();
			State buf, &state = d.unpack(buf, n->state);

			if (d.isgoal(state)) {
				handlesol(d, n);
				break;
			}

			expand(d, n, state);
		}
		res.finish();

		closed.prstats(stdout, "closed ");
		dfpair(stdout, "open list type", "%s", open.kind());
		dfpair(stdout, "node size", "%u", sizeof(Node<D, Cost>));

		return res;
	}

	Astar(void) : closed(30000001) {}

private:

	typedef typename D::State State;
	typedef typename D::PackedState PackedState;
	typedef typename D::Undo Undo;
	typedef typename D::Cost Cost;
	typedef typename D::Oper Oper;

	void expand(D &d, Node<D, Cost> *n, State &state) {
		res.expd++;

		for (unsigned int i = 0; i < d.nops(state); i++) {
			Oper op = d.nthop(state, i);
			if (op == n->pop)
				continue;
			Node<D, Cost> *k = kid(d, n, state, op);
			res.gend++;

			considerkid(d, k);
		}
	}

	void considerkid(D &d, Node<D, Cost> *k) {
		unsigned long h = k->state.hash();
		Node<D, Cost> *dup = closed.find(k->state, h);
		if (dup) {
			res.dups++;
			if (k->g >= dup->g) {
				nodes.destroy(k);
				return;
			}
			if (!open.mem(dup))
				open.pre_update(dup);

			dup->f = dup->f - dup->g + k->g;
			dup->g = k->g;
			dup->pop = k->pop;
			dup->parent = k->parent;

			if (!open.mem(dup))
				open.push(dup);
			else
				open.post_update(dup);
			nodes.destroy(k);
		} else {
			closed.add(k, h);
			open.push(k);
		}
	}

	Node<D, Cost> *kid(D &d, Node<D, Cost> *pnode, State &pstate, Oper op) {
		Node<D, Cost> *kid = nodes.construct();
		State buf, &kidst = d.applyinto(kid->state, buf, pstate, op);
		kid->g = pnode->g + d.opcost(pstate, op);
		kid->f = kid->g + d.h(kidst);
		kid->pop = d.revop(pstate, op);
		kid->parent = pnode;
		return kid;
	}

	Node<D, Cost> *init(D &d, State &s0) {
		Node<D, Cost> *n0 = nodes.construct();
		d.pack(n0->state, s0);
		n0->g = 0;
		n0->f = d.h(s0);
		n0->pop = D::Nop;
		n0->parent = NULL;
		return n0;
	}

	void handlesol(D &d, Node<D, Cost> *n) {
		res.cost = n->g;

		for ( ; n; n = n->parent) {
			State buf;
			State &state = d.unpack(buf, n->state);
			res.path.push_back(state);
		}
	}

	struct Closedops {
		static PackedState &key(Node<D, Cost> *n) { return n->state; }
		static unsigned long hash(PackedState &s) { return s.hash(); }
		static bool eq(PackedState &a, PackedState &b) { return a.eq(b); }
		static HtableEntry< Node<D, Cost> > &entry(Node<D, Cost> *n) {
			return n->closedent;
		}
	};

	Result<D> res;
	OpenList< Node<D, Cost>, Node<D, Cost>, Cost > open;
 	Htable< Closedops, PackedState&, Node<D, Cost> > closed;
	boost::object_pool< Node<D, Cost> > nodes;
};<|endoftext|>


<commit_before>#include "CellQueue.h"

#include "Assert.h"

namespace mack {

CellQueue::CellQueue() : m_head(0), m_tail(0), m_data(new Cell*[MAX_CAPACITY]) {
}

CellQueue::CellQueue(const CellQueue& other) {
    CellQueue();
    *this = other;
}

void CellQueue::operator=(const CellQueue& other) {
    int head = other._getHead();
    int tail = other._getTail();
    while (head != tail) {
        enqueue(_getData()[head]);
        head += 1;
    }
}

CellQueue::~CellQueue() {
    delete[] m_data;
}

bool CellQueue::empty() const {
    return m_head == m_tail;
}

void CellQueue::enqueue(Cell* cell) {
    m_data[m_tail] = cell;
    m_tail += (1 + MAX_CAPACITY) % MAX_CAPACITY;
}

Cell* CellQueue::dequeue() {
    ASSERT(!empty());
    Cell* data = m_data[m_head];
    m_data += (1 + MAX_CAPACITY) % MAX_CAPACITY;
    return data;
}

int CellQueue::_getHead() const {
    return m_head;
}

int CellQueue::_getTail() const {
    return m_tail;
}

Cell** CellQueue::_getData() const {
    return m_data;
}

} // namespace mack
<commit_msg>Fixed small bug<commit_after>#include "CellQueue.h"

#include "Assert.h"

namespace mack {

CellQueue::CellQueue() : m_head(0), m_tail(0), m_data(new Cell*[MAX_CAPACITY]) {
}

CellQueue::CellQueue(const CellQueue& other) {
    CellQueue();
    *this = other;
}

void CellQueue::operator=(const CellQueue& other) {
    int head = other._getHead();
    int tail = other._getTail();
    while (head != tail) {
        enqueue(_getData()[head]);
        head += 1;
    }
}

CellQueue::~CellQueue() {
    delete[] m_data;
}

bool CellQueue::empty() const {
    return m_head == m_tail;
}

void CellQueue::enqueue(Cell* cell) {
    m_data[m_tail] = cell;
    m_tail += (1 + MAX_CAPACITY) % MAX_CAPACITY;
}

Cell* CellQueue::dequeue() {
    ASSERT(!empty());
    Cell* data = m_data[m_head];
    m_head += (1 + MAX_CAPACITY) % MAX_CAPACITY;
    return data;
}

int CellQueue::_getHead() const {
    return m_head;
}

int CellQueue::_getTail() const {
    return m_tail;
}

Cell** CellQueue::_getData() const {
    return m_data;
}

} // namespace mack
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A class to Manage a growing transfer buffer.

#include "gpu/command_buffer/client/transfer_buffer.h"

#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"

namespace gpu {

AlignedRingBuffer::~AlignedRingBuffer() {
}

TransferBuffer::TransferBuffer(
    CommandBufferHelper* helper)
    : helper_(helper),
      result_size_(0),
      default_buffer_size_(0),
      min_buffer_size_(0),
      max_buffer_size_(0),
      alignment_(0),
      size_to_flush_(0),
      bytes_since_last_flush_(0),
      buffer_id_(-1),
      result_buffer_(NULL),
      result_shm_offset_(0),
      usable_(true) {
}

TransferBuffer::~TransferBuffer() {
  Free();
}

bool TransferBuffer::Initialize(
    unsigned int default_buffer_size,
    unsigned int result_size,
    unsigned int min_buffer_size,
    unsigned int max_buffer_size,
    unsigned int alignment,
    unsigned int size_to_flush) {
  result_size_ = result_size;
  default_buffer_size_ = default_buffer_size;
  min_buffer_size_ = min_buffer_size;
  max_buffer_size_ = max_buffer_size;
  alignment_ = alignment;
  size_to_flush_ = size_to_flush;
  ReallocateRingBuffer(default_buffer_size_ - result_size);
  return HaveBuffer();
}

void TransferBuffer::Free() {
  if (HaveBuffer()) {
    TRACE_EVENT0("gpu", "TransferBuffer::Free");
    helper_->Finish();
    helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
    buffer_id_ = -1;
    buffer_ = NULL;
    result_buffer_ = NULL;
    result_shm_offset_ = 0;
    ring_buffer_.reset();
    bytes_since_last_flush_ = 0;
  }
}

bool TransferBuffer::HaveBuffer() const {
  DCHECK(buffer_id_ == -1 || buffer_);
  return buffer_id_ != -1;
}

RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
  return ring_buffer_->GetOffset(pointer);
}

void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
  ring_buffer_->FreePendingToken(p, token);
  if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
    helper_->Flush();
    bytes_since_last_flush_ = 0;
  }
}

void TransferBuffer::AllocateRingBuffer(unsigned int size) {
  for (;size >= min_buffer_size_; size /= 2) {
    int32 id = -1;
    scoped_refptr<gpu::Buffer> buffer =
        helper_->command_buffer()->CreateTransferBuffer(size, &id);
    if (id != -1) {
      DCHECK(buffer);
      buffer_ = buffer;
      ring_buffer_.reset(new AlignedRingBuffer(
          alignment_,
          id,
          result_size_,
          buffer_->size() - result_size_,
          helper_,
          static_cast<char*>(buffer_->memory()) + result_size_));
      buffer_id_ = id;
      result_buffer_ = buffer_->memory();
      result_shm_offset_ = 0;
      return;
    }
    // we failed so don't try larger than this.
    max_buffer_size_ = size / 2;
  }
  usable_ = false;
}

// Returns the integer i such as 2^i <= n < 2^(i+1)
static int Log2Floor(uint32 n) {
  if (n == 0)
    return -1;
  int log = 0;
  uint32 value = n;
  for (int i = 4; i >= 0; --i) {
    int shift = (1 << i);
    uint32 x = value >> shift;
    if (x != 0) {
      value = x;
      log += shift;
    }
  }
  DCHECK_EQ(value, 1u);
  return log;
}

// Returns the integer i such as 2^(i-1) < n <= 2^i
static int Log2Ceiling(uint32 n) {
  if (n == 0) {
    return -1;
  } else {
    // Log2Floor returns -1 for 0, so the following works correctly for n=1.
    return 1 + Log2Floor(n - 1);
  }
}

static unsigned int ComputePOTSize(unsigned int dimension) {
  return (dimension == 0) ? 0 : 1 << Log2Ceiling(dimension);
}

void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
  // What size buffer would we ask for if we needed a new one?
  unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
  needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
  needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
  needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);

  if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_->size())) {
    if (HaveBuffer()) {
      Free();
    }
    AllocateRingBuffer(needed_buffer_size);
  }
}

void* TransferBuffer::AllocUpTo(
    unsigned int size, unsigned int* size_allocated) {
  DCHECK(size_allocated);

  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  *size_allocated = std::min(max_size, size);
  bytes_since_last_flush_ += *size_allocated;
  return ring_buffer_->Alloc(*size_allocated);
}

void* TransferBuffer::Alloc(unsigned int size) {
  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  if (size > max_size) {
    return NULL;
  }

  bytes_since_last_flush_ += size;
  return ring_buffer_->Alloc(size);
}

void* TransferBuffer::GetResultBuffer() {
  ReallocateRingBuffer(result_size_);
  return result_buffer_;
}

int TransferBuffer::GetResultOffset() {
  ReallocateRingBuffer(result_size_);
  return result_shm_offset_;
}

int TransferBuffer::GetShmId() {
  ReallocateRingBuffer(result_size_);
  return buffer_id_;
}

unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
  return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
}

unsigned int TransferBuffer::GetMaxAllocation() const {
  return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
}

void ScopedTransferBufferPtr::Release() {
  if (buffer_) {
    transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
    buffer_ = NULL;
    size_ = 0;
  }
}

void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
  Release();
  // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
  // that address will return a pointer just like malloc, and so that GetShmId
  // will be valid. That has the side effect that we'll insert a token on free.
  // We could add code skip the token for a zero size buffer but it doesn't seem
  // worth the complication.
  buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
}

}  // namespace gpu
<commit_msg>Use base::bits::Log2{Floor,Ceiling} instead of redefining them in TransferBuffer.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A class to Manage a growing transfer buffer.

#include "gpu/command_buffer/client/transfer_buffer.h"

#include "base/bits.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"

namespace gpu {

AlignedRingBuffer::~AlignedRingBuffer() {
}

TransferBuffer::TransferBuffer(
    CommandBufferHelper* helper)
    : helper_(helper),
      result_size_(0),
      default_buffer_size_(0),
      min_buffer_size_(0),
      max_buffer_size_(0),
      alignment_(0),
      size_to_flush_(0),
      bytes_since_last_flush_(0),
      buffer_id_(-1),
      result_buffer_(NULL),
      result_shm_offset_(0),
      usable_(true) {
}

TransferBuffer::~TransferBuffer() {
  Free();
}

bool TransferBuffer::Initialize(
    unsigned int default_buffer_size,
    unsigned int result_size,
    unsigned int min_buffer_size,
    unsigned int max_buffer_size,
    unsigned int alignment,
    unsigned int size_to_flush) {
  result_size_ = result_size;
  default_buffer_size_ = default_buffer_size;
  min_buffer_size_ = min_buffer_size;
  max_buffer_size_ = max_buffer_size;
  alignment_ = alignment;
  size_to_flush_ = size_to_flush;
  ReallocateRingBuffer(default_buffer_size_ - result_size);
  return HaveBuffer();
}

void TransferBuffer::Free() {
  if (HaveBuffer()) {
    TRACE_EVENT0("gpu", "TransferBuffer::Free");
    helper_->Finish();
    helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
    buffer_id_ = -1;
    buffer_ = NULL;
    result_buffer_ = NULL;
    result_shm_offset_ = 0;
    ring_buffer_.reset();
    bytes_since_last_flush_ = 0;
  }
}

bool TransferBuffer::HaveBuffer() const {
  DCHECK(buffer_id_ == -1 || buffer_);
  return buffer_id_ != -1;
}

RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
  return ring_buffer_->GetOffset(pointer);
}

void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
  ring_buffer_->FreePendingToken(p, token);
  if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
    helper_->Flush();
    bytes_since_last_flush_ = 0;
  }
}

void TransferBuffer::AllocateRingBuffer(unsigned int size) {
  for (;size >= min_buffer_size_; size /= 2) {
    int32 id = -1;
    scoped_refptr<gpu::Buffer> buffer =
        helper_->command_buffer()->CreateTransferBuffer(size, &id);
    if (id != -1) {
      DCHECK(buffer);
      buffer_ = buffer;
      ring_buffer_.reset(new AlignedRingBuffer(
          alignment_,
          id,
          result_size_,
          buffer_->size() - result_size_,
          helper_,
          static_cast<char*>(buffer_->memory()) + result_size_));
      buffer_id_ = id;
      result_buffer_ = buffer_->memory();
      result_shm_offset_ = 0;
      return;
    }
    // we failed so don't try larger than this.
    max_buffer_size_ = size / 2;
  }
  usable_ = false;
}

static unsigned int ComputePOTSize(unsigned int dimension) {
  return (dimension == 0) ? 0 : 1 << base::bits::Log2Ceiling(dimension);
}

void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
  // What size buffer would we ask for if we needed a new one?
  unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
  needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
  needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
  needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);

  if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_->size())) {
    if (HaveBuffer()) {
      Free();
    }
    AllocateRingBuffer(needed_buffer_size);
  }
}

void* TransferBuffer::AllocUpTo(
    unsigned int size, unsigned int* size_allocated) {
  DCHECK(size_allocated);

  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  *size_allocated = std::min(max_size, size);
  bytes_since_last_flush_ += *size_allocated;
  return ring_buffer_->Alloc(*size_allocated);
}

void* TransferBuffer::Alloc(unsigned int size) {
  ReallocateRingBuffer(size);

  if (!HaveBuffer()) {
    return NULL;
  }

  unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
  if (size > max_size) {
    return NULL;
  }

  bytes_since_last_flush_ += size;
  return ring_buffer_->Alloc(size);
}

void* TransferBuffer::GetResultBuffer() {
  ReallocateRingBuffer(result_size_);
  return result_buffer_;
}

int TransferBuffer::GetResultOffset() {
  ReallocateRingBuffer(result_size_);
  return result_shm_offset_;
}

int TransferBuffer::GetShmId() {
  ReallocateRingBuffer(result_size_);
  return buffer_id_;
}

unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
  return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
}

unsigned int TransferBuffer::GetMaxAllocation() const {
  return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
}

void ScopedTransferBufferPtr::Release() {
  if (buffer_) {
    transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
    buffer_ = NULL;
    size_ = 0;
  }
}

void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
  Release();
  // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
  // that address will return a pointer just like malloc, and so that GetShmId
  // will be valid. That has the side effect that we'll insert a token on free.
  // We could add code skip the token for a zero size buffer but it doesn't seem
  // worth the complication.
  buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
}

}  // namespace gpu
<|endoftext|>


<commit_before>//
// Created by sancar koyunlu on 6/24/13.
// Copyright (c) 2013 hazelcast. All rights reserved.

#include "hazelcast/client/spi/ServerListenerService.h"
#include "hazelcast/client/serialization/pimpl/SerializationService.h"
#include "hazelcast/client/spi/InvocationService.h"
#include "hazelcast/client/impl/PortableRequest.h"
#include "hazelcast/client/impl/BaseEventHandler.h"
#include "hazelcast/client/connection/ConnectionManager.h"
#include "hazelcast/client/connection/Connection.h"
#include "hazelcast/client/spi/ClientContext.h"
#include "hazelcast/client/impl/BaseRemoveListenerRequest.h"

namespace hazelcast {
    namespace client {
        namespace spi {

            ServerListenerService::ServerListenerService(spi::ClientContext &clientContext)
            :clientContext(clientContext) {

            };

            std::string ServerListenerService::listen(const impl::PortableRequest *registrationRequest, int partitionId, impl::BaseEventHandler *handler) {
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future;
                future = clientContext.getInvocationService().invokeOnKeyOwner(registrationRequest, handler, partitionId);
                boost::shared_ptr<std::string> registrationId = clientContext.getSerializationService().toObject<std::string>(future->get());
                handler->registrationId = *registrationId;
                registerListener(registrationId, registrationRequest->callId);

                return *registrationId;
            }

            std::string ServerListenerService::listen(const impl::PortableRequest *registrationRequest, impl::BaseEventHandler *handler) {
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future;
                future = clientContext.getInvocationService().invokeOnRandomTarget(registrationRequest, handler);
                boost::shared_ptr<std::string> registrationId = clientContext.getSerializationService().toObject<std::string>(future->get());
                handler->registrationId = *registrationId;
                registerListener(registrationId, registrationRequest->callId);

                return *registrationId;
            }

            bool ServerListenerService::stopListening(impl::BaseRemoveListenerRequest *request, const std::string &registrationId) {
                std::string resolvedRegistrationId = registrationId;
                bool isValidId = deRegisterListener(resolvedRegistrationId);
                if (!isValidId) {
                    delete request;
                    return false;
                }
                request->setRegistrationId(resolvedRegistrationId);
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future = clientContext.getInvocationService().invokeOnRandomTarget(request);
                bool result = clientContext.getSerializationService().toObject<bool>(future->get());
                return result;
            }

            void ServerListenerService::registerListener(boost::shared_ptr<std::string> registrationId, int callId) {
                registrationAliasMap.put(*registrationId, registrationId);
                registrationIdMap.put(*registrationId, boost::shared_ptr<int>(new int(callId)));
            }

            void ServerListenerService::reRegisterListener(const std::string &registrationId, boost::shared_ptr<std::string> alias, int callId) {
                boost::shared_ptr<const std::string> oldAlias = registrationAliasMap.put(registrationId, alias);
                if (oldAlias.get() != NULL) {
                    registrationIdMap.remove(*oldAlias);
                    registrationIdMap.put(*alias, boost::shared_ptr<int>(new int(callId)));
                }
            }

            bool ServerListenerService::deRegisterListener(std::string &registrationId) {
                boost::shared_ptr<const std::string> uuid = registrationAliasMap.remove(registrationId);
                if (uuid != NULL) {
                    registrationId = *uuid;
                    boost::shared_ptr<int> callId = registrationIdMap.remove(*uuid);
                    clientContext.getConnectionManager().removeEventHandler(*callId);
                    return true;
                }
                return false;
            }

            void ServerListenerService::retryFailedListener(boost::shared_ptr<connection::CallPromise> failedListener) {
                boost::shared_ptr<connection::Connection> connection;
                try {
                    connection::ConnectionManager &cm = clientContext.getConnectionManager();
                    connection = cm.getRandomConnection(spi::InvocationService::RETRY_COUNT);
                } catch(exception::IException &) {
                    util::LockGuard lockGuard(failedListenerLock);
                    failedListeners.push_back(failedListener);
                    return;
                }
                connection->registerAndEnqueue(failedListener);
            }

            void ServerListenerService::triggerFailedListeners() {
                std::vector< boost::shared_ptr<connection::CallPromise> >::iterator it;
                std::vector< boost::shared_ptr<connection::CallPromise> > newFailedListeners;

                util::LockGuard lockGuard(failedListenerLock);
                for (it = failedListeners.begin(); it != failedListeners.end(); ++it) {
                    boost::shared_ptr<connection::Connection> connection;
                    try {
                        connection::ConnectionManager &cm = clientContext.getConnectionManager();
                        connection = cm.getRandomConnection(spi::InvocationService::RETRY_COUNT);
                    } catch(exception::IOException &) {
                        newFailedListeners.push_back(*it);
                        continue;
                    }
                    connection->registerAndEnqueue(*it);
                }
                failedListeners = newFailedListeners;
            }
        }
    }
}

<commit_msg>fix on ServerListenerService<commit_after>//
// Created by sancar koyunlu on 6/24/13.
// Copyright (c) 2013 hazelcast. All rights reserved.

#include "hazelcast/client/spi/ServerListenerService.h"
#include "hazelcast/client/serialization/pimpl/SerializationService.h"
#include "hazelcast/client/spi/InvocationService.h"
#include "hazelcast/client/impl/PortableRequest.h"
#include "hazelcast/client/impl/BaseEventHandler.h"
#include "hazelcast/client/connection/ConnectionManager.h"
#include "hazelcast/client/connection/Connection.h"
#include "hazelcast/client/spi/ClientContext.h"
#include "hazelcast/client/impl/BaseRemoveListenerRequest.h"

namespace hazelcast {
    namespace client {
        namespace spi {

            ServerListenerService::ServerListenerService(spi::ClientContext &clientContext)
            :clientContext(clientContext) {

            };

            std::string ServerListenerService::listen(const impl::PortableRequest *registrationRequest, int partitionId, impl::BaseEventHandler *handler) {
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future;
                future = clientContext.getInvocationService().invokeOnKeyOwner(registrationRequest, handler, partitionId);
                boost::shared_ptr<std::string> registrationId = clientContext.getSerializationService().toObject<std::string>(future->get());
                handler->registrationId = *registrationId;
                registerListener(registrationId, registrationRequest->callId);

                return *registrationId;
            }

            std::string ServerListenerService::listen(const impl::PortableRequest *registrationRequest, impl::BaseEventHandler *handler) {
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future;
                future = clientContext.getInvocationService().invokeOnRandomTarget(registrationRequest, handler);
                boost::shared_ptr<std::string> registrationId = clientContext.getSerializationService().toObject<std::string>(future->get());
                handler->registrationId = *registrationId;
                registerListener(registrationId, registrationRequest->callId);

                return *registrationId;
            }

            bool ServerListenerService::stopListening(impl::BaseRemoveListenerRequest *request, const std::string &registrationId) {
                std::string resolvedRegistrationId = registrationId;
                bool isValidId = deRegisterListener(resolvedRegistrationId);
                if (!isValidId) {
                    delete request;
                    return false;
                }
                request->setRegistrationId(resolvedRegistrationId);
                boost::shared_ptr< util::Future<serialization::pimpl::Data> >  future = clientContext.getInvocationService().invokeOnRandomTarget(request);
                bool result = *(clientContext.getSerializationService().toObject<bool>(future->get()));
                return result;
            }

            void ServerListenerService::registerListener(boost::shared_ptr<std::string> registrationId, int callId) {
                registrationAliasMap.put(*registrationId, registrationId);
                registrationIdMap.put(*registrationId, boost::shared_ptr<int>(new int(callId)));
            }

            void ServerListenerService::reRegisterListener(const std::string &registrationId, boost::shared_ptr<std::string> alias, int callId) {
                boost::shared_ptr<const std::string> oldAlias = registrationAliasMap.put(registrationId, alias);
                if (oldAlias.get() != NULL) {
                    registrationIdMap.remove(*oldAlias);
                    registrationIdMap.put(*alias, boost::shared_ptr<int>(new int(callId)));
                }
            }

            bool ServerListenerService::deRegisterListener(std::string &registrationId) {
                boost::shared_ptr<const std::string> uuid = registrationAliasMap.remove(registrationId);
                if (uuid != NULL) {
                    registrationId = *uuid;
                    boost::shared_ptr<int> callId = registrationIdMap.remove(*uuid);
                    clientContext.getConnectionManager().removeEventHandler(*callId);
                    return true;
                }
                return false;
            }

            void ServerListenerService::retryFailedListener(boost::shared_ptr<connection::CallPromise> failedListener) {
                boost::shared_ptr<connection::Connection> connection;
                try {
                    connection::ConnectionManager &cm = clientContext.getConnectionManager();
                    connection = cm.getRandomConnection(spi::InvocationService::RETRY_COUNT);
                } catch(exception::IException &) {
                    util::LockGuard lockGuard(failedListenerLock);
                    failedListeners.push_back(failedListener);
                    return;
                }
                connection->registerAndEnqueue(failedListener);
            }

            void ServerListenerService::triggerFailedListeners() {
                std::vector< boost::shared_ptr<connection::CallPromise> >::iterator it;
                std::vector< boost::shared_ptr<connection::CallPromise> > newFailedListeners;

                util::LockGuard lockGuard(failedListenerLock);
                for (it = failedListeners.begin(); it != failedListeners.end(); ++it) {
                    boost::shared_ptr<connection::Connection> connection;
                    try {
                        connection::ConnectionManager &cm = clientContext.getConnectionManager();
                        connection = cm.getRandomConnection(spi::InvocationService::RETRY_COUNT);
                    } catch(exception::IOException &) {
                        newFailedListeners.push_back(*it);
                        continue;
                    }
                    connection->registerAndEnqueue(*it);
                }
                failedListeners = newFailedListeners;
            }
        }
    }
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "libtorrent/packet_buffer.hpp"

using libtorrent::packet_buffer;

// test packet_buffer
TORRENT_TEST(packet_buffer)
{
	packet_buffer pb;

	TEST_EQUAL(pb.capacity(), 0);
	TEST_EQUAL(pb.size(), 0);
	TEST_EQUAL(pb.span(), 0);

	pb.insert(123, (void*)123);
	TEST_EQUAL(pb.at(123 + 16), 0);

	TEST_CHECK(pb.at(123) == (void*)123);
	TEST_CHECK(pb.capacity() > 0);
	TEST_EQUAL(pb.size(), 1);
	TEST_EQUAL(pb.span(), 1);
	TEST_EQUAL(pb.cursor(), 123);

	pb.insert(125, (void*)125);

	TEST_CHECK(pb.at(125) == (void*)125);
	TEST_EQUAL(pb.size(), 2);
	TEST_EQUAL(pb.span(), 3);
	TEST_EQUAL(pb.cursor(), 123);

	pb.insert(500, (void*)500);
	TEST_EQUAL(pb.size(), 3);
	TEST_EQUAL(pb.span(), 501 - 123);
	TEST_EQUAL(pb.capacity(), 512);

	pb.insert(500, (void*)501);
	TEST_EQUAL(pb.size(), 3);
	pb.insert(500, (void*)500);
	TEST_EQUAL(pb.size(), 3);

	TEST_CHECK(pb.remove(123) == (void*)123);
	TEST_EQUAL(pb.size(), 2);
	TEST_EQUAL(pb.span(), 501 - 125);
	TEST_EQUAL(pb.cursor(), 125);
	TEST_CHECK(pb.remove(125) == (void*)125);
	TEST_EQUAL(pb.size(), 1);
	TEST_EQUAL(pb.span(), 1);
	TEST_EQUAL(pb.cursor(), 500);

	TEST_CHECK(pb.remove(500) == (void*)500);
	TEST_EQUAL(pb.size(), 0);
	TEST_EQUAL(pb.span(), 0);

	for (int i = 0; i < 0xff; ++i)
	{
		int index = (i + 0xfff0) & 0xffff;
		pb.insert(index, (void*)(index + 1));
		fprintf(stderr, "insert: %u (mask: %x)\n", index, int(pb.capacity() - 1));
		TEST_EQUAL(pb.capacity(), 512);
		if (i >= 14)
		{
			index = (index - 14) & 0xffff;
			fprintf(stderr, "remove: %u\n", index);
			TEST_CHECK(pb.remove(index) == (void*)(index + 1));
			TEST_EQUAL(pb.size(), 14);
		}
	}
}

TORRENT_TEST(packet_buffer_wrap)
{
	// test wrapping the indices
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfffe, (void*)1);
	TEST_CHECK(pb.at(0xfffe) == (void*)1);

	pb.insert(2, (void*)2);
	TEST_CHECK(pb.at(2) == (void*)2);

	pb.remove(0xfffe);
	TEST_CHECK(pb.at(0xfffe) == (void*)0);
	TEST_CHECK(pb.at(2) == (void*)2);
}

TORRENT_TEST(packet_buffer_wrap2)
{
	// test wrapping the indices
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfff3, (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)1);

	int new_index = (0xfff3 + pb.capacity()) & 0xffff;
	pb.insert(new_index, (void*)2);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	void* old = pb.remove(0xfff3);
	TEST_CHECK(old == (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)0);
	TEST_CHECK(pb.at(new_index) == (void*)2);
}

TORRENT_TEST(packet_buffer_reverse_wrap)
{
	// test wrapping the indices backwards
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfff3, (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)1);

	int new_index = (0xfff3 + pb.capacity()) & 0xffff;
	pb.insert(new_index, (void*)2);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	void* old = pb.remove(0xfff3);
	TEST_CHECK(old == (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)0);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	pb.insert(0xffff, (void*)0xffff);
}

<commit_msg>test names<commit_after>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "test.hpp"
#include "libtorrent/packet_buffer.hpp"

using libtorrent::packet_buffer;

// test packet_buffer
TORRENT_TEST(insert)
{
	packet_buffer pb;

	TEST_EQUAL(pb.capacity(), 0);
	TEST_EQUAL(pb.size(), 0);
	TEST_EQUAL(pb.span(), 0);

	pb.insert(123, (void*)123);
	TEST_EQUAL(pb.at(123 + 16), 0);

	TEST_CHECK(pb.at(123) == (void*)123);
	TEST_CHECK(pb.capacity() > 0);
	TEST_EQUAL(pb.size(), 1);
	TEST_EQUAL(pb.span(), 1);
	TEST_EQUAL(pb.cursor(), 123);

	pb.insert(125, (void*)125);

	TEST_CHECK(pb.at(125) == (void*)125);
	TEST_EQUAL(pb.size(), 2);
	TEST_EQUAL(pb.span(), 3);
	TEST_EQUAL(pb.cursor(), 123);

	pb.insert(500, (void*)500);
	TEST_EQUAL(pb.size(), 3);
	TEST_EQUAL(pb.span(), 501 - 123);
	TEST_EQUAL(pb.capacity(), 512);

	pb.insert(500, (void*)501);
	TEST_EQUAL(pb.size(), 3);
	pb.insert(500, (void*)500);
	TEST_EQUAL(pb.size(), 3);

	TEST_CHECK(pb.remove(123) == (void*)123);
	TEST_EQUAL(pb.size(), 2);
	TEST_EQUAL(pb.span(), 501 - 125);
	TEST_EQUAL(pb.cursor(), 125);
	TEST_CHECK(pb.remove(125) == (void*)125);
	TEST_EQUAL(pb.size(), 1);
	TEST_EQUAL(pb.span(), 1);
	TEST_EQUAL(pb.cursor(), 500);

	TEST_CHECK(pb.remove(500) == (void*)500);
	TEST_EQUAL(pb.size(), 0);
	TEST_EQUAL(pb.span(), 0);

	for (int i = 0; i < 0xff; ++i)
	{
		int index = (i + 0xfff0) & 0xffff;
		pb.insert(index, (void*)(index + 1));
		fprintf(stderr, "insert: %u (mask: %x)\n", index, int(pb.capacity() - 1));
		TEST_EQUAL(pb.capacity(), 512);
		if (i >= 14)
		{
			index = (index - 14) & 0xffff;
			fprintf(stderr, "remove: %u\n", index);
			TEST_CHECK(pb.remove(index) == (void*)(index + 1));
			TEST_EQUAL(pb.size(), 14);
		}
	}
}

TORRENT_TEST(wrap)
{
	// test wrapping the indices
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfffe, (void*)1);
	TEST_CHECK(pb.at(0xfffe) == (void*)1);

	pb.insert(2, (void*)2);
	TEST_CHECK(pb.at(2) == (void*)2);

	pb.remove(0xfffe);
	TEST_CHECK(pb.at(0xfffe) == (void*)0);
	TEST_CHECK(pb.at(2) == (void*)2);
}

TORRENT_TEST(wrap2)
{
	// test wrapping the indices
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfff3, (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)1);

	int new_index = (0xfff3 + pb.capacity()) & 0xffff;
	pb.insert(new_index, (void*)2);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	void* old = pb.remove(0xfff3);
	TEST_CHECK(old == (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)0);
	TEST_CHECK(pb.at(new_index) == (void*)2);
}

TORRENT_TEST(reverse_wrap)
{
	// test wrapping the indices backwards
	packet_buffer pb;

	TEST_EQUAL(pb.size(), 0);

	pb.insert(0xfff3, (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)1);

	int new_index = (0xfff3 + pb.capacity()) & 0xffff;
	pb.insert(new_index, (void*)2);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	void* old = pb.remove(0xfff3);
	TEST_CHECK(old == (void*)1);
	TEST_CHECK(pb.at(0xfff3) == (void*)0);
	TEST_CHECK(pb.at(new_index) == (void*)2);

	pb.insert(0xffff, (void*)0xffff);
}

<|endoftext|>


<commit_before>/*
Copyright 2016 Fixstars Corporation

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 <iostream>
#include <iomanip>
#include <string>
#include <chrono>

#include <cuda_runtime.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/version.hpp>

#include <libsgm.h>

#define ASSERT_MSG(expr, msg) \
	if (!(expr)) { \
		std::cerr << msg << std::endl; \
		std::exit(EXIT_FAILURE); \
	} \

struct device_buffer
{
	device_buffer() : data(nullptr) {}
	device_buffer(size_t count) { allocate(count); }
	void allocate(size_t count) { cudaMalloc(&data, count); }
	~device_buffer() { cudaFree(data); }
	void* data;
};

template <class... Args>
static std::string format_string(const char* fmt, Args... args)
{
	const int BUF_SIZE = 1024;
	char buf[BUF_SIZE];
	std::snprintf(buf, BUF_SIZE, fmt, args...);
	return std::string(buf);
}

int main(int argc, char* argv[])
{
	if (argc < 3) {
		std::cout << "usage: " << argv[0] << " left-image-format right-image-format [disp_size]" << std::endl;
		std::exit(EXIT_FAILURE);
	}

	const int first_frame = 1;

	cv::Mat I1 = cv::imread(format_string(argv[1], first_frame), -1);
	cv::Mat I2 = cv::imread(format_string(argv[2], first_frame), -1);
	const int disp_size = argc >= 4 ? std::stoi(argv[3]) : 128;

	ASSERT_MSG(!I1.empty() && !I2.empty(), "imread failed.");
	ASSERT_MSG(I1.size() == I2.size() && I1.type() == I2.type(), "input images must be same size and type.");
	ASSERT_MSG(I1.type() == CV_8U || I1.type() == CV_16U, "input image format must be CV_8U or CV_16U.");
	ASSERT_MSG(disp_size == 64 || disp_size == 128 || disp_size == 256, "disparity size must be 64, 128 or 256.");

	const int width = I1.cols;
	const int height = I1.rows;

	const int input_depth = I1.type() == CV_8U ? 8 : 16;
	const int input_bytes = input_depth * width * height / 8;
	const int output_depth = 8;
	const int output_bytes = output_depth * width * height / 8;

	sgm::StereoSGM sgm(width, height, disp_size, input_depth, output_depth, sgm::EXECUTE_INOUT_CUDA2CUDA);

	cv::Mat disparity(height, width, output_depth == 8 ? CV_8U : CV_16U);
	cv::Mat disparity_8u, disparity_color;

	device_buffer d_I1(input_bytes), d_I2(input_bytes), d_disparity(output_bytes);

	for (int frame_no = first_frame;; frame_no++) {

		I1 = cv::imread(format_string(argv[1], frame_no), -1);
		I2 = cv::imread(format_string(argv[2], frame_no), -1);
		if (I1.empty() || I2.empty()) {
			frame_no = first_frame;
			continue;
		}

		cudaMemcpy(d_I1.data, I1.data, input_bytes, cudaMemcpyHostToDevice);
		cudaMemcpy(d_I2.data, I2.data, input_bytes, cudaMemcpyHostToDevice);

		const auto t1 = std::chrono::system_clock::now();

		sgm.execute(d_I1.data, d_I2.data, d_disparity.data);
		cudaDeviceSynchronize();

		const auto t2 = std::chrono::system_clock::now();
		const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
		const double fps = 1e6 / duration;

		cudaMemcpy(disparity.data, d_disparity.data, output_bytes, cudaMemcpyDeviceToHost);

		// draw results
		if (I1.type() != CV_8U) {
			cv::normalize(I1, I1, 0, 255, cv::NORM_MINMAX);
			I1.convertTo(I1, CV_8U);
		}

		disparity.convertTo(disparity_8u, CV_8U, 255. / disp_size);
		cv::applyColorMap(disparity_8u, disparity_color, cv::COLORMAP_JET);
		disparity_color.setTo(cv::Scalar(0, 0, 0), disparity == static_cast<std::uint8_t>(sgm.get_invalid_disparity()));
		cv::putText(disparity_color, format_string("sgm execution time: %4.1f[msec] %4.1f[FPS]", 1e-3 * duration, fps),
			cv::Point(50, 50), 2, 0.75, cv::Scalar(255, 255, 255));

		cv::imshow("left image", I1);
		cv::imshow("disparity", disparity_color);
		const char c = cv::waitKey(1);
		if (c == 27) // ESC
			break;
	}

	return 0;
}
<commit_msg>Fix generality at sample/movie<commit_after>/*
Copyright 2016 Fixstars Corporation

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 <iostream>
#include <iomanip>
#include <string>
#include <chrono>

#include <cuda_runtime.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/version.hpp>

#include <libsgm.h>

#define ASSERT_MSG(expr, msg) \
	if (!(expr)) { \
		std::cerr << msg << std::endl; \
		std::exit(EXIT_FAILURE); \
	} \

struct device_buffer
{
	device_buffer() : data(nullptr) {}
	device_buffer(size_t count) { allocate(count); }
	void allocate(size_t count) { cudaMalloc(&data, count); }
	~device_buffer() { cudaFree(data); }
	void* data;
};

template <class... Args>
static std::string format_string(const char* fmt, Args... args)
{
	const int BUF_SIZE = 1024;
	char buf[BUF_SIZE];
	std::snprintf(buf, BUF_SIZE, fmt, args...);
	return std::string(buf);
}

int main(int argc, char* argv[])
{
	if (argc < 3) {
		std::cout << "usage: " << argv[0] << " left-image-format right-image-format [disp_size]" << std::endl;
		std::exit(EXIT_FAILURE);
	}

	const int first_frame = 1;

	cv::Mat I1 = cv::imread(format_string(argv[1], first_frame), -1);
	cv::Mat I2 = cv::imread(format_string(argv[2], first_frame), -1);
	const int disp_size = argc >= 4 ? std::stoi(argv[3]) : 128;

	ASSERT_MSG(!I1.empty() && !I2.empty(), "imread failed.");
	ASSERT_MSG(I1.size() == I2.size() && I1.type() == I2.type(), "input images must be same size and type.");
	ASSERT_MSG(I1.type() == CV_8U || I1.type() == CV_16U, "input image format must be CV_8U or CV_16U.");
	ASSERT_MSG(disp_size == 64 || disp_size == 128 || disp_size == 256, "disparity size must be 64, 128 or 256.");

	const int width = I1.cols;
	const int height = I1.rows;

	const int input_depth = I1.type() == CV_8U ? 8 : 16;
	const int input_bytes = input_depth * width * height / 8;
	const int output_depth = disp_size < 256 ? 8 : 16;
	const int output_bytes = output_depth * width * height / 8;

	sgm::StereoSGM sgm(width, height, disp_size, input_depth, output_depth, sgm::EXECUTE_INOUT_CUDA2CUDA);

	const int invalid_disp = output_depth == 8
			? static_cast< uint8_t>(sgm.get_invalid_disparity())
			: static_cast<uint16_t>(sgm.get_invalid_disparity());

	cv::Mat disparity(height, width, output_depth == 8 ? CV_8U : CV_16U);
	cv::Mat disparity_8u, disparity_color;

	device_buffer d_I1(input_bytes), d_I2(input_bytes), d_disparity(output_bytes);

	for (int frame_no = first_frame;; frame_no++) {

		I1 = cv::imread(format_string(argv[1], frame_no), -1);
		I2 = cv::imread(format_string(argv[2], frame_no), -1);
		if (I1.empty() || I2.empty()) {
			frame_no = first_frame;
			continue;
		}

		cudaMemcpy(d_I1.data, I1.data, input_bytes, cudaMemcpyHostToDevice);
		cudaMemcpy(d_I2.data, I2.data, input_bytes, cudaMemcpyHostToDevice);

		const auto t1 = std::chrono::system_clock::now();

		sgm.execute(d_I1.data, d_I2.data, d_disparity.data);
		cudaDeviceSynchronize();

		const auto t2 = std::chrono::system_clock::now();
		const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
		const double fps = 1e6 / duration;

		cudaMemcpy(disparity.data, d_disparity.data, output_bytes, cudaMemcpyDeviceToHost);

		// draw results
		if (I1.type() != CV_8U) {
			cv::normalize(I1, I1, 0, 255, cv::NORM_MINMAX);
			I1.convertTo(I1, CV_8U);
		}

		disparity.convertTo(disparity_8u, CV_8U, 255. / disp_size);
		cv::applyColorMap(disparity_8u, disparity_color, cv::COLORMAP_JET);
		disparity_color.setTo(cv::Scalar(0, 0, 0), disparity == invalid_disp);
		cv::putText(disparity_color, format_string("sgm execution time: %4.1f[msec] %4.1f[FPS]", 1e-3 * duration, fps),
			cv::Point(50, 50), 2, 0.75, cv::Scalar(255, 255, 255));

		cv::imshow("left image", I1);
		cv::imshow("disparity", disparity_color);
		const char c = cv::waitKey(1);
		if (c == 27) // ESC
			break;
	}

	return 0;
}
<|endoftext|>