<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bwtree_index.cpp
//
// Identification: src/backend/index/bwtree_index.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "index/bwtree_index.h"

#include "common/logger.h"
#include "index/index_key.h"
#include "index/scan_optimizer.h"
#include "statistics/stats_aggregator.h"
#include "storage/tuple.h"

namespace peloton {
namespace index {

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::BWTreeIndex(IndexMetadata *metadata)
    :  // Base class
      Index{metadata},
      // Key "less than" relation comparator
      comparator{},
      // Key equality checker
      equals{},
      // Key hash function
      hash_func{},
      // NOTE: These two arguments need to be constructed in advance
      // and do not have trivial constructor
      //
      // NOTE 2: We set the first parameter to false to disable automatic GC
      //
      container{false, comparator, equals, hash_func} {
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::~BWTreeIndex() {}

/*
 * InsertEntry() - insert a key-value pair into the map
 *
 * If the key value pair already exists in the map, just return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::InsertEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool ret = container.Insert(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * DeleteEntry() - Removes a key-value pair
 *
 * If the key-value pair does not exists yet in the map return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::DeleteEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);
  size_t delete_count = 0;

  // In Delete() since we just use the value for comparison (i.e. read-only)
  // it is unnecessary for us to allocate memory
  bool ret = container.Delete(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexDeletes(
        delete_count, metadata);
  }
  return ret;
}

BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::CondInsertEntry(
    const storage::Tuple *key, ItemPointer *value,
    std::function<bool(const void *)> predicate) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool predicate_satisfied = false;

  // This function will complete them in one step
  // predicate will be set to nullptr if the predicate
  // returns true for some value
  bool ret = container.ConditionalInsert(index_key, value, predicate,
                                         &predicate_satisfied);

  // If predicate is not satisfied then we know insertion successes
  if (predicate_satisfied == false) {
    // So it should always succeed?
    assert(ret == true);
  } else {
    assert(ret == false);
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * Scan() - Scans a range inside the index using index scan optimizer
 *
 * The scan optimizer specifies whether a scan is point query, full scan
 * or interval scan. For all of these cases the corresponding functions from
 * the index is called, and all elements are returned in result vector
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::Scan(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    const ScanDirectionType &scan_direction, std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p) {
  // This is a hack - we do not support backward scan
  if (scan_direction == SCAN_DIRECTION_TYPE_INVALID) {
    throw Exception("Invalid scan direction \n");
  }

  LOG_TRACE("Scan() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_key_p);

    // Note: We could call ScanKey() to achieve better modularity
    // (slightly less code), but since ScanKey() is a virtual function
    // this would induce an overhead for point query, which must be highly
    // optimized and super fast
    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

/*
 * ScanLimit() - Scan the index with predicate and limit/offset
 *
 * This function scans the index using the given index optimizer's low key and
 * high key. In addition to merely doing the scan, it checks scan direction
 * and uses either begin() or end() iterator to scan the index, and stops
 * after offset + limit elements are scanned, and limit elements are finally
 * returned
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanLimit(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    const ScanDirectionType &scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p,
    uint64_t limit,
    uint64_t offset) {
  (void)limit;
  (void)offset;
  LOG_TRACE("ScanLimit() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_tuple_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_tuple_key_p);

    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanAllKeys(std::vector<ValueType> &result) {
  auto it = container.Begin();

  // scan all entries
  while (it.IsEnd() == false) {
    result.push_back(it->second);
    it++;
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanKey(const storage::Tuple *key,
                                std::vector<ValueType> &result) {
  KeyType index_key;
  index_key.SetFromKey(key);

  // This function in BwTree fills a given vector
  container.GetValue(index_key, result);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
std::string BWTREE_INDEX_TYPE::GetTypeName() const { return "BWTree"; }

// IMPORTANT: Make sure you don't exceed CompactIntegerKey_MAX_SLOTS

template class BWTreeIndex<CompactIntsKey<1>, ItemPointer *,
                           CompactIntsComparator<1>,
                           CompactIntsEqualityChecker<1>, CompactIntsHasher<1>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<2>, ItemPointer *,
                           CompactIntsComparator<2>,
                           CompactIntsEqualityChecker<2>, CompactIntsHasher<2>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<3>, ItemPointer *,
                           CompactIntsComparator<3>,
                           CompactIntsEqualityChecker<3>, CompactIntsHasher<3>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<4>, ItemPointer *,
                           CompactIntsComparator<4>,
                           CompactIntsEqualityChecker<4>, CompactIntsHasher<4>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Generic key
template class BWTreeIndex<GenericKey<4>, ItemPointer *,
                           FastGenericComparator<4>, GenericEqualityChecker<4>,
                           GenericHasher<4>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<8>, ItemPointer *,
                           FastGenericComparator<8>, GenericEqualityChecker<8>,
                           GenericHasher<8>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<16>, ItemPointer *,
                           FastGenericComparator<16>,
                           GenericEqualityChecker<16>, GenericHasher<16>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<64>, ItemPointer *,
                           FastGenericComparator<64>,
                           GenericEqualityChecker<64>, GenericHasher<64>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<256>, ItemPointer *,
                           FastGenericComparator<256>,
                           GenericEqualityChecker<256>, GenericHasher<256>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Tuple key
template class BWTreeIndex<TupleKey, ItemPointer *, TupleKeyComparator,
                           TupleKeyEqualityChecker, TupleKeyHasher,
                           ItemPointerComparator, ItemPointerHashFunc>;

}  // End index namespace
}  // End peloton namespace
<commit_msg>Not using scan_direction for now...<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// bwtree_index.cpp
//
// Identification: src/backend/index/bwtree_index.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
#include "index/bwtree_index.h"

#include "common/logger.h"
#include "index/index_key.h"
#include "index/scan_optimizer.h"
#include "statistics/stats_aggregator.h"
#include "storage/tuple.h"

namespace peloton {
namespace index {

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::BWTreeIndex(IndexMetadata *metadata)
    :  // Base class
      Index{metadata},
      // Key "less than" relation comparator
      comparator{},
      // Key equality checker
      equals{},
      // Key hash function
      hash_func{},
      // NOTE: These two arguments need to be constructed in advance
      // and do not have trivial constructor
      //
      // NOTE 2: We set the first parameter to false to disable automatic GC
      //
      container{false, comparator, equals, hash_func} {
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
BWTREE_INDEX_TYPE::~BWTreeIndex() {}

/*
 * InsertEntry() - insert a key-value pair into the map
 *
 * If the key value pair already exists in the map, just return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::InsertEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool ret = container.Insert(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * DeleteEntry() - Removes a key-value pair
 *
 * If the key-value pair does not exists yet in the map return false
 */
BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::DeleteEntry(const storage::Tuple *key,
                                    ItemPointer *value) {
  KeyType index_key;
  index_key.SetFromKey(key);
  size_t delete_count = 0;

  // In Delete() since we just use the value for comparison (i.e. read-only)
  // it is unnecessary for us to allocate memory
  bool ret = container.Delete(index_key, value);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexDeletes(
        delete_count, metadata);
  }
  return ret;
}

BWTREE_TEMPLATE_ARGUMENTS
bool BWTREE_INDEX_TYPE::CondInsertEntry(
    const storage::Tuple *key, ItemPointer *value,
    std::function<bool(const void *)> predicate) {
  KeyType index_key;
  index_key.SetFromKey(key);

  bool predicate_satisfied = false;

  // This function will complete them in one step
  // predicate will be set to nullptr if the predicate
  // returns true for some value
  bool ret = container.ConditionalInsert(index_key, value, predicate,
                                         &predicate_satisfied);

  // If predicate is not satisfied then we know insertion successes
  if (predicate_satisfied == false) {
    // So it should always succeed?
    assert(ret == true);
  } else {
    assert(ret == false);
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexInserts(metadata);
  }

  return ret;
}

/*
 * Scan() - Scans a range inside the index using index scan optimizer
 *
 * The scan optimizer specifies whether a scan is point query, full scan
 * or interval scan. For all of these cases the corresponding functions from
 * the index is called, and all elements are returned in result vector
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::Scan(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    const ScanDirectionType &scan_direction, std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p) {
  // This is a hack - we do not support backward scan
  if (scan_direction == SCAN_DIRECTION_TYPE_INVALID) {
    throw Exception("Invalid scan direction \n");
  }

  LOG_TRACE("Scan() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_key_p);

    // Note: We could call ScanKey() to achieve better modularity
    // (slightly less code), but since ScanKey() is a virtual function
    // this would induce an overhead for point query, which must be highly
    // optimized and super fast
    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

/*
 * ScanLimit() - Scan the index with predicate and limit/offset
 *
 * This function scans the index using the given index optimizer's low key and
 * high key. In addition to merely doing the scan, it checks scan direction
 * and uses either begin() or end() iterator to scan the index, and stops
 * after offset + limit elements are scanned, and limit elements are finally
 * returned
 */
BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanLimit(
    UNUSED_ATTRIBUTE const std::vector<type::Value> &value_list,
    UNUSED_ATTRIBUTE const std::vector<oid_t> &tuple_column_id_list,
    UNUSED_ATTRIBUTE const std::vector<ExpressionType> &expr_list,
    const ScanDirectionType &scan_direction,
    std::vector<ValueType> &result,
    const ConjunctionScanPredicate *csp_p,
    uint64_t limit,
    uint64_t offset) {
  (void)limit;
  (void)offset;
  (void)scan_direction;
  LOG_TRACE("ScanLimit() Point Query = %d; Full Scan = %d ",
            csp_p->IsPointQuery(),
            csp_p->IsFullIndexScan());

  if (csp_p->IsPointQuery() == true) {
    const storage::Tuple *point_query_tuple_key_p = csp_p->GetPointQueryKey();

    KeyType point_query_key;
    point_query_key.SetFromKey(point_query_tuple_key_p);

    container.GetValue(point_query_key, result);
  } else if (csp_p->IsFullIndexScan() == true) {
    // If it is a full index scan, then just do the scan
    // until we have reached the end of the index by the same
    // we take the snapshot of the last leaf node
    for (auto scan_itr = container.Begin(); (scan_itr.IsEnd() == false);
         scan_itr++) {
      result.push_back(scan_itr->second);
    }  // for it from begin() to end()
  } else {
    const storage::Tuple *low_key_p = csp_p->GetLowKey();
    const storage::Tuple *high_key_p = csp_p->GetHighKey();

    LOG_TRACE("Partial scan low key: %s\n high key: %s",
              low_key_p->GetInfo().c_str(), high_key_p->GetInfo().c_str());

    // Construct low key and high key in KeyType form, rather than
    // the standard in-memory tuple
    KeyType index_low_key;
    KeyType index_high_key;
    index_low_key.SetFromKey(low_key_p);
    index_high_key.SetFromKey(high_key_p);

    // We use bwtree Begin() to first reach the lower bound
    // of the search key
    // Also we keep scanning until we have reached the end of the index
    // or we have seen a key higher than the high key
    for (auto scan_itr = container.Begin(index_low_key);
         (scan_itr.IsEnd() == false) &&
             (container.KeyCmpLessEqual(scan_itr->first, index_high_key));
         scan_itr++) {
      result.push_back(scan_itr->second);
    }
  }  // if is full scan

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanAllKeys(std::vector<ValueType> &result) {
  auto it = container.Begin();

  // scan all entries
  while (it.IsEnd() == false) {
    result.push_back(it->second);
    it++;
  }

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }
  return;
}

BWTREE_TEMPLATE_ARGUMENTS
void BWTREE_INDEX_TYPE::ScanKey(const storage::Tuple *key,
                                std::vector<ValueType> &result) {
  KeyType index_key;
  index_key.SetFromKey(key);

  // This function in BwTree fills a given vector
  container.GetValue(index_key, result);

  if (FLAGS_stats_mode != STATS_TYPE_INVALID) {
    stats::BackendStatsContext::GetInstance()->IncrementIndexReads(
        result.size(), metadata);
  }

  return;
}

BWTREE_TEMPLATE_ARGUMENTS
std::string BWTREE_INDEX_TYPE::GetTypeName() const { return "BWTree"; }

// IMPORTANT: Make sure you don't exceed CompactIntegerKey_MAX_SLOTS

template class BWTreeIndex<CompactIntsKey<1>, ItemPointer *,
                           CompactIntsComparator<1>,
                           CompactIntsEqualityChecker<1>, CompactIntsHasher<1>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<2>, ItemPointer *,
                           CompactIntsComparator<2>,
                           CompactIntsEqualityChecker<2>, CompactIntsHasher<2>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<3>, ItemPointer *,
                           CompactIntsComparator<3>,
                           CompactIntsEqualityChecker<3>, CompactIntsHasher<3>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<CompactIntsKey<4>, ItemPointer *,
                           CompactIntsComparator<4>,
                           CompactIntsEqualityChecker<4>, CompactIntsHasher<4>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Generic key
template class BWTreeIndex<GenericKey<4>, ItemPointer *,
                           FastGenericComparator<4>, GenericEqualityChecker<4>,
                           GenericHasher<4>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<8>, ItemPointer *,
                           FastGenericComparator<8>, GenericEqualityChecker<8>,
                           GenericHasher<8>, ItemPointerComparator,
                           ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<16>, ItemPointer *,
                           FastGenericComparator<16>,
                           GenericEqualityChecker<16>, GenericHasher<16>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<64>, ItemPointer *,
                           FastGenericComparator<64>,
                           GenericEqualityChecker<64>, GenericHasher<64>,
                           ItemPointerComparator, ItemPointerHashFunc>;
template class BWTreeIndex<GenericKey<256>, ItemPointer *,
                           FastGenericComparator<256>,
                           GenericEqualityChecker<256>, GenericHasher<256>,
                           ItemPointerComparator, ItemPointerHashFunc>;

// Tuple key
template class BWTreeIndex<TupleKey, ItemPointer *, TupleKeyComparator,
                           TupleKeyEqualityChecker, TupleKeyHasher,
                           ItemPointerComparator, ItemPointerHashFunc>;

}  // End index namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcess'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/regex.h>
#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/configdlg.h>
#include <wx/extension/frame.h>
#include <wx/extension/log.h>
#include <wx/extension/util.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/frame.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcess, wxProcess)
  EVT_TIMER(-1, wxExProcess::OnTimer)
END_EVENT_TABLE()

wxExProcess* wxExProcess::m_Self = NULL;
wxString wxExProcess::m_Command;

wxExProcess::wxExProcess()
  : m_Frame(NULL)
  , m_ListView(NULL)
{
}

wxExProcess::wxExProcess(
  wxExFrameWithHistory* frame,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Frame(frame)
  , m_ListView(NULL)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcess::CheckInput()
{
  if (m_ListView == NULL)
  {
    return false;
  }

  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    const wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)", wxRE_ADVANCED);

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItem item(m_ListView, fn);
      item.Insert();
      item.SetItem(_("Line"), line);
      item.SetItem(_("Line No"), lineno);
    }
    else
    {
      m_ListView->InsertItem(m_ListView->GetItemCount(), line, -1);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_ListView->GetSelectedItemCount() == 0)
    {
      m_ListView->EnsureVisible(m_ListView->GetItemCount() - 1);
    }

#if wxUSE_STATUSBAR
    m_ListView->UpdateStatusBar();
#endif
  }

  return hasInput;
}

int wxExProcess::ConfigDialog(
  wxWindow* parent,
  const wxString& title)
{
  std::vector<wxExConfigItem> v;

  v.push_back(wxExConfigItem(
    _("Process"),
    CONFIG_COMBOBOX,
    wxEmptyString));

  v.push_back(wxExConfigItem(
    _("Process folder"),
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  const auto result = wxExConfigDialog(parent,
    v,
    title).ShowModal();

  if (result == wxID_OK)
  {
    m_Command = wxExConfigFirstOf(_("Process"));
  }

  return result;
}

long wxExProcess::Execute()
{
  if (m_Command.empty())
  {
    if (ConfigDialog(m_ListView) == wxID_CANCEL)
    {
      return 0;
    }
  }

  wxString cwd;
  const wxString dir = wxExConfigFirstOf(_("Process folder"));

  if (!dir.empty())
  {
    cwd = wxGetCwd();
    if (!wxSetWorkingDirectory(dir))
    {
      wxLogError(_("Cannot set working directory"));
      return 0;
    }
  }

  m_ListView = m_Frame->Activate(wxExListViewStandard::LIST_PROCESS);

  if (m_ListView == NULL)
  {
    wxLogError(_("No listview to collect output"));
    return 0;
  }

  const long pid = wxExecute(m_Command, wxEXEC_ASYNC, this);

  if (pid > 0)
  {
    SetPid(pid);

#if wxUSE_STATUSBAR
    wxExFrame::StatusText(m_Command);
#endif
    wxExLog::Get()->Log(m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot execute") + ": " + m_Command);
  }

  if (!cwd.empty())
  {
    wxSetWorkingDirectory(cwd);
  }

  return pid;
}

wxExProcess* wxExProcess::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExProcess();
    m_Self->m_Command = wxExConfigFirstOf(_("Process"));
  }

  return m_Self;
}

bool wxExProcess::IsRunning() const
{
  if (GetPid() < 0)
  {
    return false;
  }

  return wxProcess::Exists(GetPid());
}

wxKillError wxExProcess::Kill(wxSignal sig)
{
  if (!Exists(GetPid()))
  {
    return wxKILL_NO_PROCESS;
  }

  m_Timer.Stop();

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(_("Stopped"));
#endif

  DeletePendingEvents();

  // Next statement causes wxGTK to crash, so outcommented.
#ifndef __WXGTK__
  delete this;
#endif

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcess::OnTerminate(
  int WXUNUSED(pid),
  int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(_("Ready"));
#endif

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(wxTheApp->GetTopWindow(), event);
}

void wxExProcess::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}

wxExProcess* wxExProcess::Set(wxExProcess* process)
{
  wxExProcess* old = m_Self;
  m_Self = process;
  return old;
}
<commit_msg>don't use scope<commit_after>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcess'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/regex.h>
#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/configdlg.h>
#include <wx/extension/frame.h>
#include <wx/extension/log.h>
#include <wx/extension/util.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/frame.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcess, wxProcess)
  EVT_TIMER(-1, wxExProcess::OnTimer)
END_EVENT_TABLE()

wxExProcess* wxExProcess::m_Self = NULL;
wxString wxExProcess::m_Command;

wxExProcess::wxExProcess()
  : m_Frame(NULL)
  , m_ListView(NULL)
{
}

wxExProcess::wxExProcess(
  wxExFrameWithHistory* frame,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Frame(frame)
  , m_ListView(NULL)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcess::CheckInput()
{
  if (m_ListView == NULL)
  {
    return false;
  }

  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    const wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)", wxRE_ADVANCED);

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItem item(m_ListView, fn);
      item.Insert();
      item.SetItem(_("Line"), line);
      item.SetItem(_("Line No"), lineno);
    }
    else
    {
      m_ListView->InsertItem(m_ListView->GetItemCount(), line, -1);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_ListView->GetSelectedItemCount() == 0)
    {
      m_ListView->EnsureVisible(m_ListView->GetItemCount() - 1);
    }

#if wxUSE_STATUSBAR
    m_ListView->UpdateStatusBar();
#endif
  }

  return hasInput;
}

int wxExProcess::ConfigDialog(
  wxWindow* parent,
  const wxString& title)
{
  std::vector<wxExConfigItem> v;

  v.push_back(wxExConfigItem(
    _("Process"),
    CONFIG_COMBOBOX,
    wxEmptyString));

  v.push_back(wxExConfigItem(
    _("Process folder"),
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  const auto result = wxExConfigDialog(parent,
    v,
    title).ShowModal();

  if (result == wxID_OK)
  {
    m_Command = wxExConfigFirstOf(_("Process"));
  }

  return result;
}

long wxExProcess::Execute()
{
  if (m_Command.empty())
  {
    if (ConfigDialog(m_ListView) == wxID_CANCEL)
    {
      return 0;
    }
  }

  wxString cwd;
  const wxString dir = wxExConfigFirstOf(_("Process folder"));

  if (!dir.empty())
  {
    cwd = wxGetCwd();
    if (!wxSetWorkingDirectory(dir))
    {
      wxLogError(_("Cannot set working directory"));
      return 0;
    }
  }

  m_ListView = m_Frame->Activate(wxExListViewStandard::LIST_PROCESS);

  if (m_ListView == NULL)
  {
    wxLogError(_("No listview to collect output"));
    return 0;
  }

  const long pid = wxExecute(m_Command, wxEXEC_ASYNC, this);

  if (pid > 0)
  {
    SetPid(pid);

#if wxUSE_STATUSBAR
    wxExFrame::StatusText(m_Command);
#endif
    wxExLog::Get()->Log(m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot execute") + ": " + m_Command);
  }

  if (!cwd.empty())
  {
    wxSetWorkingDirectory(cwd);
  }

  return pid;
}

wxExProcess* wxExProcess::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExProcess();
    m_Self->m_Command = wxExConfigFirstOf(_("Process"));
  }

  return m_Self;
}

bool wxExProcess::IsRunning() const
{
  if (GetPid() < 0)
  {
    return false;
  }

  return Exists(GetPid());
}

wxKillError wxExProcess::Kill(wxSignal sig)
{
  if (!Exists(GetPid()))
  {
    return wxKILL_NO_PROCESS;
  }

  m_Timer.Stop();

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(_("Stopped"));
#endif

  DeletePendingEvents();

  // Next statement causes wxGTK to crash, so outcommented.
#ifndef __WXGTK__
  delete this;
#endif

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcess::OnTerminate(
  int WXUNUSED(pid),
  int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(_("Ready"));
#endif

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(wxTheApp->GetTopWindow(), event);
}

void wxExProcess::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}

wxExProcess* wxExProcess::Set(wxExProcess* process)
{
  wxExProcess* old = m_Self;
  m_Self = process;
  return old;
}
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcessWithListView'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/app.h>
#include <wx/extension/configdialog.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcessWithListView, wxProcess)
  EVT_TIMER(-1, wxExProcessWithListView::OnTimer)
END_EVENT_TABLE()

wxString wxExProcessWithListView::m_Command = "";

wxExProcessWithListView::wxExProcessWithListView(
  wxExListViewFile* listview,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Owner(listview)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcessWithListView::CheckInput()
{
  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)");

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItemWithFileName item(m_Owner, fn.GetFullPath());
      item.Insert();
      item.SetColumnText(_("Line"), line);
      item.SetColumnText(_("Line No"), lineno);
    }
    else
    {
      wxExListItemWithFileName item(m_Owner, wxEmptyString); // wxExListItem gives incorrect image
      item.Insert();
      item.SetColumnText(_("Line"), line);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_Owner->GetSelectedItemCount() == 0)
    {
      m_Owner->EnsureVisible(m_Owner->GetItemCount() - 1);
    }

    m_Owner->UpdateStatusBar();
  }

  return hasInput;
}

int wxExProcessWithListView::ConfigDialog()
{
  std::vector<wxExConfigItem> v;
  v.push_back(wxExConfigItem(_("Process"), CONFIG_COMBOBOX, wxEmptyString, true));
  v.push_back(wxExConfigItem(_("In folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  const int result = wxExConfigDialog(NULL,
    wxExApp::GetConfig(),
    v,
    _("Select Process")).ShowModal();

  if (result == wxID_OK)
  {
    wxSetWorkingDirectory(wxExApp::GetConfig(_("In folder")));
    m_Command = wxExApp::GetConfig(_("Process"));
  }

  return result;
}

long wxExProcessWithListView::Execute()
{
  long pid;

  if ((pid = wxExecute(m_Command, wxEXEC_ASYNC, this)) > 0)
  {
    SetPid(pid);

    wxExFrame::StatusText(m_Command);
    wxExApp::Log(_("Running process") + ": " + m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot run process") + ": " + m_Command);
  }

  return pid;
}

void wxExProcessWithListView::InitCommandFromConfig()
{
  // The process is a combobox, we want only the first from the list,
  // so use the separator.
  m_Command = wxExApp::GetConfig(_("Process"), wxEmptyString, '@');
}

wxKillError wxExProcessWithListView::Kill(wxSignal sig)
{
  m_Timer.Stop();

  wxExFrame::StatusText(_("Stopped"));

  DeletePendingEvents();

  delete this;

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcessWithListView::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

  wxExFrame::StatusText(_("Ready"));

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(m_Owner, event);
}

void wxExProcessWithListView::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}
<commit_msg>so we need the default separator for retrieving value from the config<commit_after>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcessWithListView'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/app.h>
#include <wx/extension/configdialog.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcessWithListView, wxProcess)
  EVT_TIMER(-1, wxExProcessWithListView::OnTimer)
END_EVENT_TABLE()

wxString wxExProcessWithListView::m_Command = "";

wxExProcessWithListView::wxExProcessWithListView(
  wxExListViewFile* listview,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Owner(listview)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcessWithListView::CheckInput()
{
  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)");

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItemWithFileName item(m_Owner, fn.GetFullPath());
      item.Insert();
      item.SetColumnText(_("Line"), line);
      item.SetColumnText(_("Line No"), lineno);
    }
    else
    {
      // wxExListItem gives incorrect image
      wxExListItemWithFileName item(m_Owner, wxEmptyString);
      item.Insert();
      item.SetColumnText(_("Line"), line);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_Owner->GetSelectedItemCount() == 0)
    {
      m_Owner->EnsureVisible(m_Owner->GetItemCount() - 1);
    }

    m_Owner->UpdateStatusBar();
  }

  return hasInput;
}

int wxExProcessWithListView::ConfigDialog()
{
  std::vector<wxExConfigItem> v;
  v.push_back(wxExConfigItem(_("Process"), CONFIG_COMBOBOX, wxEmptyString, true));
  v.push_back(wxExConfigItem(_("In folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  const int result = wxExConfigDialog(NULL,
    wxExApp::GetConfig(),
    v,
    _("Select Process")).ShowModal();

  if (result == wxID_OK)
  {
    wxSetWorkingDirectory(wxExApp::GetConfig(_("In folder")));
    m_Command = wxExApp::GetConfig(_("Process"));
  }

  return result;
}

long wxExProcessWithListView::Execute()
{
  long pid;

  if ((pid = wxExecute(m_Command, wxEXEC_ASYNC, this)) > 0)
  {
    SetPid(pid);

    wxExFrame::StatusText(m_Command);
    wxExApp::Log(_("Running process") + ": " + m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot run process") + ": " + m_Command);
  }

  return pid;
}

void wxExProcessWithListView::InitCommandFromConfig()
{
  // The process is a combobox, we want only the first from the list,
  // so use the default separator, causing only first field to be returned.
  m_Command = wxExApp::GetConfig(_("Process"));
}

wxKillError wxExProcessWithListView::Kill(wxSignal sig)
{
  m_Timer.Stop();

  wxExFrame::StatusText(_("Stopped"));

  DeletePendingEvents();

  delete this;

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcessWithListView::OnTerminate(
  int WXUNUSED(pid),
  int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

  wxExFrame::StatusText(_("Ready"));

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(m_Owner, event);
}

void wxExProcessWithListView::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}
<|endoftext|>


<commit_before>/*
 * main.cpp (Tutorial03_Texturing)
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "../tutorial.h"

#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"

class Tutorial03 : public Tutorial
{

    LLGL::ShaderProgram*    shaderProgram   = nullptr;
    LLGL::GraphicsPipeline* pipeline        = nullptr;
    LLGL::VertexBuffer*     vertexBuffer    = nullptr;
    LLGL::Texture*          colorMap        = nullptr;
    LLGL::Sampler*          sampler[5]      = { nullptr };
    int                     samplerIndex    = 0;

public:

    Tutorial03() :
        Tutorial( "Direct3D11", L"LLGL Tutorial 03: Texturing")
    {
        // Check if samplers are supported
        auto renderCaps = renderer->QueryRenderingCaps();

        if (!renderCaps.hasSamplers)
            throw std::runtime_error("samplers are not supported by this renderer");

        // Create all graphics objects
        auto vertexFormat = CreateBuffers();
        shaderProgram = LoadStandardShaderProgram(vertexFormat);
        CreatePipelines();
        CreateTextures();
        CreateSamplers();

        // Print some information on the standard output
        std::cout << "press TAB KEY to switch between five different texture samplers" << std::endl;
    }

    LLGL::VertexFormat CreateBuffers()
    {
        // Specify vertex format
        LLGL::VertexFormat vertexFormat;
        vertexFormat.AddAttribute("position", LLGL::DataType::Float32, 2);
        vertexFormat.AddAttribute("texCoord", LLGL::DataType::Float32, 2);

        // Define vertex buffer data
        struct Vertex
        {
            Gs::Vector2f position;
            Gs::Vector2f texCoord;
        };

        std::vector<Vertex> vertices =
        {
            { { -1, -3 }, { 0, 4 } },
            { { -1,  1 }, { 0, 0 } },
            { {  3,  1 }, { 4, 0 } },
        };

        // Create vertex buffer
        vertexBuffer = CreateVertexBuffer(vertices, vertexFormat);

        return vertexFormat;
    }

    void CreatePipelines()
    {
        // Create graphics pipeline
        LLGL::GraphicsPipelineDescriptor pipelineDesc;
        {
            pipelineDesc.shaderProgram = shaderProgram;
        }
        pipeline = renderer->CreateGraphicsPipeline(pipelineDesc);
    }

    void CreateTextures()
    {
        std::string texFilename = "colorMap.png";

        // Load image data from file (using STBI library, see http://nothings.org/stb_image.h)
        int texWidth = 0, texHeight = 0, texComponents = 0;

        unsigned char* imageBuffer = stbi_load(texFilename.c_str(), &texWidth, &texHeight, &texComponents, 3);
        if (!imageBuffer)
            throw std::runtime_error("failed to open file: \"" + texFilename + "\"");

        // Create texture
        colorMap = renderer->CreateTexture();

        // Upload image data onto hardware texture
        LLGL::ImageDataDescriptor imageDesc;
        {
            // Set image buffer source for texture initial data
            imageDesc.data          = imageBuffer;

            // Set image buffer color format
            imageDesc.dataFormat    = (texComponents == 3 ? LLGL::ImageFormat::RGB : LLGL::ImageFormat::RGBA);

            // Set image buffer data type (unsigned char = 8-bit unsigned integer)
            imageDesc.dataType      = LLGL::DataType::UInt8;
        }
        renderer->SetupTexture2D(*colorMap, LLGL::TextureFormat::RGBA, Gs::Vector2i(texWidth, texHeight), &imageDesc);

        // Generate all MIP-maps (MIP = "Multum in Parvo", or "a multitude in a small space")
        // see https://developer.valvesoftware.com/wiki/MIP_Mapping
        // see http://whatis.techtarget.com/definition/MIP-map
        context->GenerateMips(*colorMap);

        // Release image data
        stbi_image_free(imageBuffer);
    }

    void CreateSamplers()
    {
        // Create 1st sampler state with default settings
        LLGL::SamplerDescriptor samplerDesc;
        sampler[0] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.mipMapLODBias = 3.0f;
        sampler[1] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.minFilter = LLGL::TextureFilter::Nearest;
        sampler[2] = renderer->CreateSampler(samplerDesc);

        // Create 3rd sampler state with clamped texture wrap modes
        samplerDesc.minFilter = LLGL::TextureFilter::Linear;
        samplerDesc.mipMapLODBias = 0.0f;
        samplerDesc.textureWrapU = LLGL::TextureWrap::Clamp;
        sampler[3] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.textureWrapV = LLGL::TextureWrap::Mirror;
        sampler[4] = renderer->CreateSampler(samplerDesc);
    }

private:

    void OnDrawFrame() override
    {
        // Examine user input
        if (input->KeyDown(LLGL::Key::Tab))
            samplerIndex = (samplerIndex + 1) % 5;

        // Clear color buffer
        context->ClearBuffers(LLGL::ClearBuffersFlags::Color);

        // Set graphics pipeline and vertex buffer
        context->SetGraphicsPipeline(*pipeline);
        context->SetVertexBuffer(*vertexBuffer);

        // Set texture and sampler state on slot index 0
        context->SetTexture(*colorMap, 0);
        context->SetSampler(*sampler[samplerIndex], 0);

        // Draw fullscreen triangle
        context->Draw(3, 0);

        // Present result on the screen
        context->Present();
    }

};

LLGL_IMPLEMENT_TUTORIAL(Tutorial03);

<commit_msg>Updated Tutorial03.<commit_after>/*
 * main.cpp (Tutorial03_Texturing)
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "../tutorial.h"

#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"

class Tutorial03 : public Tutorial
{

    LLGL::ShaderProgram*    shaderProgram   = nullptr;
    LLGL::GraphicsPipeline* pipeline        = nullptr;
    LLGL::VertexBuffer*     vertexBuffer    = nullptr;
    LLGL::Texture*          colorMap        = nullptr;
    LLGL::Sampler*          sampler[5]      = { nullptr };
    int                     samplerIndex    = 0;

public:

    Tutorial03() :
        Tutorial( "Direct3D11", L"LLGL Tutorial 03: Texturing")
    {
        // Check if samplers are supported
        auto renderCaps = renderer->QueryRenderingCaps();

        if (!renderCaps.hasSamplers)
            throw std::runtime_error("samplers are not supported by this renderer");

        // Create all graphics objects
        auto vertexFormat = CreateBuffers();
        shaderProgram = LoadStandardShaderProgram(vertexFormat);
        CreatePipelines();
        CreateTextures();
        CreateSamplers();

        // Print some information on the standard output
        std::cout << "press TAB KEY to switch between five different texture samplers" << std::endl;
    }

    LLGL::VertexFormat CreateBuffers()
    {
        // Specify vertex format
        LLGL::VertexFormat vertexFormat;
        vertexFormat.AddAttribute("position", LLGL::DataType::Float32, 2);
        vertexFormat.AddAttribute("texCoord", LLGL::DataType::Float32, 2);

        // Define vertex buffer data
        struct Vertex
        {
            Gs::Vector2f position;
            Gs::Vector2f texCoord;
        };

        std::vector<Vertex> vertices =
        {
            { { -1, -3 }, { 0, 4 } },
            { { -1,  1 }, { 0, 0 } },
            { {  3,  1 }, { 4, 0 } },
        };

        // Create vertex buffer
        vertexBuffer = CreateVertexBuffer(vertices, vertexFormat);

        return vertexFormat;
    }

    void CreatePipelines()
    {
        // Create graphics pipeline
        LLGL::GraphicsPipelineDescriptor pipelineDesc;
        {
            pipelineDesc.shaderProgram = shaderProgram;
        }
        pipeline = renderer->CreateGraphicsPipeline(pipelineDesc);
    }

    void CreateTextures()
    {
        std::string texFilename = "colorMap.png";

        // Load image data from file (using STBI library, see http://nothings.org/stb_image.h)
        int texWidth = 0, texHeight = 0, texComponents = 0;

        unsigned char* imageBuffer = stbi_load(texFilename.c_str(), &texWidth, &texHeight, &texComponents, 4);
        if (!imageBuffer)
            throw std::runtime_error("failed to open file: \"" + texFilename + "\"");

        // Create texture
        colorMap = renderer->CreateTexture();

        // Upload image data onto hardware texture
        LLGL::ImageDataDescriptor imageDesc;
        {
            // Set image buffer source for texture initial data
            imageDesc.data          = imageBuffer;

            // Set image buffer color format
            imageDesc.dataFormat    = LLGL::ImageFormat::RGBA;

            // Set image buffer data type (unsigned char = 8-bit unsigned integer)
            imageDesc.dataType      = LLGL::DataType::UInt8;
        }
        renderer->SetupTexture2D(*colorMap, LLGL::TextureFormat::RGBA, Gs::Vector2i(texWidth, texHeight), &imageDesc);

        // Generate all MIP-maps (MIP = "Multum in Parvo", or "a multitude in a small space")
        // see https://developer.valvesoftware.com/wiki/MIP_Mapping
        // see http://whatis.techtarget.com/definition/MIP-map
        context->GenerateMips(*colorMap);

        // Release image data
        stbi_image_free(imageBuffer);
    }

    void CreateSamplers()
    {
        // Create 1st sampler state with default settings
        LLGL::SamplerDescriptor samplerDesc;
        sampler[0] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.mipMapLODBias = 3.0f;
        sampler[1] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.minFilter = LLGL::TextureFilter::Nearest;
        sampler[2] = renderer->CreateSampler(samplerDesc);

        // Create 3rd sampler state with clamped texture wrap modes
        samplerDesc.minFilter = LLGL::TextureFilter::Linear;
        samplerDesc.mipMapLODBias = 0.0f;
        samplerDesc.textureWrapU = LLGL::TextureWrap::Clamp;
        sampler[3] = renderer->CreateSampler(samplerDesc);

        // Create 2nd sampler state with MIP-map bias
        samplerDesc.textureWrapV = LLGL::TextureWrap::Mirror;
        sampler[4] = renderer->CreateSampler(samplerDesc);
    }

private:

    void OnDrawFrame() override
    {
        // Examine user input
        if (input->KeyDown(LLGL::Key::Tab))
            samplerIndex = (samplerIndex + 1) % 5;

        // Clear color buffer
        context->ClearBuffers(LLGL::ClearBuffersFlags::Color);

        // Set graphics pipeline and vertex buffer
        context->SetGraphicsPipeline(*pipeline);
        context->SetVertexBuffer(*vertexBuffer);

        // Set texture and sampler state on slot index 0
        context->SetTexture(*colorMap, 0);
        context->SetSampler(*sampler[samplerIndex], 0);

        // Draw fullscreen triangle
        context->Draw(3, 0);

        // Present result on the screen
        context->Present();
    }

};

LLGL_IMPLEMENT_TUTORIAL(Tutorial03);

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE wdrr_fixed_multiplexed_queue

#include <memory>

#include "caf/test/unit_test.hpp"

#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "caf/intrusive/wdrr_fixed_multiplexed_queue.hpp"

using namespace caf;
using namespace caf::intrusive;

namespace {

struct inode : singly_linked<inode> {
  int value;
  inode(int x = 0) : value(x) {
    // nop
  }
};

std::string to_string(const inode& x) {
  return std::to_string(x.value);
}

class high_prio_queue;

struct inode_policy {
  using mapped_type = inode;

  using task_size_type = int;

  using deficit_type = int;

  using deleter_type = std::default_delete<mapped_type>;

  using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;

  static inline task_size_type task_size(const mapped_type&) {
    return 1;
  }

  static inline size_t id_of(const inode& x) {
    return x.value % 3;
  }

  template <class Queue>
  deficit_type quantum(const Queue&, deficit_type x) {
    return x;
  }

  deficit_type quantum(const high_prio_queue&, deficit_type x) {
    return enable_priorities ? 2 * x : x;
  }

  bool enable_priorities = false;
};

class high_prio_queue : public drr_queue<inode_policy> {
public:
  using super = drr_queue<inode_policy>;

  using super::super;
};

using nested_queue_type = drr_queue<inode_policy>;

using queue_type = wdrr_fixed_multiplexed_queue<inode_policy,
                                                high_prio_queue,
                                                nested_queue_type,
                                                nested_queue_type>;

struct fetch_helper {
  std::string result;

  template <size_t I, class Queue>
  task_result operator()(std::integral_constant<size_t, I>, const Queue&,
                         inode& x) {
    if (!result.empty())
      result += ',';
    result += std::to_string(I);
    result += ':';
    result += to_string(x);
    return task_result::resume;
  };
};

struct fixture {
  inode_policy policy;
  queue_type queue{policy, policy, policy, policy};

  void fill(queue_type&) {
    // nop
  }

  template <class T, class... Ts>
  void fill(queue_type& q, T x, Ts... xs) {
    q.emplace_back(x);
    fill(q, xs...);
  }

  std::string fetch(int quantum) {
    std::string result;
    auto f = [&](size_t id, drr_queue<inode_policy>&, inode& x) {
      if (!result.empty())
        result += ',';
      result += std::to_string(id);
      result += ':';
      result += to_string(x);
      return task_result::resume;
    };
    queue.new_round(quantum, f);
    return result;
  }
};

} // namespace <anonymous>

CAF_TEST_FIXTURE_SCOPE(wdrr_fixed_multiplexed_queue_tests, fixture)

CAF_TEST(default_constructed) {
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(new_round) {
  fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12);
  // Allow f to consume 2 items per nested queue.
  fetch_helper f;
  auto round_result = queue.new_round(2, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:3,0:6,1:1,1:4,2:2,2:5");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Allow f to consume one more item from each queue.
  f.result.clear();
  round_result = queue.new_round(1, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:9,1:7,2:8");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Allow f to consume the remainder, i.e., 12.
  f.result.clear();
  round_result = queue.new_round(1000, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:12");
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(priorities) {
  queue.policy().enable_priorities = true;
  fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  // Allow f to consume 2 items from the high priority and 1 item otherwise.
  CAF_CHECK_EQUAL(fetch(1), "0:3,0:6,1:1,2:2");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Drain the high-priority queue with one item left per other queue.
  CAF_CHECK_EQUAL(fetch(1), "0:9,1:4,2:5");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Drain queue.
  CAF_CHECK_EQUAL(fetch(1000), "1:7,2:8");
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(peek_all) {
  auto queue_to_string = [&] {
    std::string str;
    auto peek_fun = [&](const inode& x) {
      if (!str.empty())
        str += ", ";
      str += std::to_string(x.value);
    };
    queue.peek_all(peek_fun);
    return str;
  };
  CAF_CHECK_EQUAL(queue_to_string(), "");
  queue.emplace_back(1);
  CAF_CHECK_EQUAL(queue_to_string(), "1");
  queue.emplace_back(2);
  CAF_CHECK_EQUAL(queue_to_string(), "1, 2");
  queue.emplace_back(3);
  // Lists are iterated in order and 3 is stored in the first queue for
  // `x mod 3 == 0` values.
  CAF_CHECK_EQUAL(queue_to_string(), "3, 1, 2");
  queue.emplace_back(4);
  CAF_CHECK_EQUAL(queue_to_string(), "3, 1, 4, 2");
}

CAF_TEST(to_string) {
  CAF_CHECK_EQUAL(deep_to_string(queue), "[]");
  fill(queue, 1, 2, 3, 4);
  CAF_CHECK_EQUAL(deep_to_string(queue), "[3, 1, 4, 2]");
}

CAF_TEST_FIXTURE_SCOPE_END()
<commit_msg>Remove extra ";"<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE wdrr_fixed_multiplexed_queue

#include <memory>

#include "caf/test/unit_test.hpp"

#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "caf/intrusive/wdrr_fixed_multiplexed_queue.hpp"

using namespace caf;
using namespace caf::intrusive;

namespace {

struct inode : singly_linked<inode> {
  int value;
  inode(int x = 0) : value(x) {
    // nop
  }
};

std::string to_string(const inode& x) {
  return std::to_string(x.value);
}

class high_prio_queue;

struct inode_policy {
  using mapped_type = inode;

  using task_size_type = int;

  using deficit_type = int;

  using deleter_type = std::default_delete<mapped_type>;

  using unique_pointer = std::unique_ptr<mapped_type, deleter_type>;

  static inline task_size_type task_size(const mapped_type&) {
    return 1;
  }

  static inline size_t id_of(const inode& x) {
    return x.value % 3;
  }

  template <class Queue>
  deficit_type quantum(const Queue&, deficit_type x) {
    return x;
  }

  deficit_type quantum(const high_prio_queue&, deficit_type x) {
    return enable_priorities ? 2 * x : x;
  }

  bool enable_priorities = false;
};

class high_prio_queue : public drr_queue<inode_policy> {
public:
  using super = drr_queue<inode_policy>;

  using super::super;
};

using nested_queue_type = drr_queue<inode_policy>;

using queue_type = wdrr_fixed_multiplexed_queue<inode_policy,
                                                high_prio_queue,
                                                nested_queue_type,
                                                nested_queue_type>;

struct fetch_helper {
  std::string result;

  template <size_t I, class Queue>
  task_result operator()(std::integral_constant<size_t, I>, const Queue&,
                         inode& x) {
    if (!result.empty())
      result += ',';
    result += std::to_string(I);
    result += ':';
    result += to_string(x);
    return task_result::resume;
  }
};

struct fixture {
  inode_policy policy;
  queue_type queue{policy, policy, policy, policy};

  void fill(queue_type&) {
    // nop
  }

  template <class T, class... Ts>
  void fill(queue_type& q, T x, Ts... xs) {
    q.emplace_back(x);
    fill(q, xs...);
  }

  std::string fetch(int quantum) {
    std::string result;
    auto f = [&](size_t id, drr_queue<inode_policy>&, inode& x) {
      if (!result.empty())
        result += ',';
      result += std::to_string(id);
      result += ':';
      result += to_string(x);
      return task_result::resume;
    };
    queue.new_round(quantum, f);
    return result;
  }
};

} // namespace <anonymous>

CAF_TEST_FIXTURE_SCOPE(wdrr_fixed_multiplexed_queue_tests, fixture)

CAF_TEST(default_constructed) {
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(new_round) {
  fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12);
  // Allow f to consume 2 items per nested queue.
  fetch_helper f;
  auto round_result = queue.new_round(2, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:3,0:6,1:1,1:4,2:2,2:5");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Allow f to consume one more item from each queue.
  f.result.clear();
  round_result = queue.new_round(1, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:9,1:7,2:8");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Allow f to consume the remainder, i.e., 12.
  f.result.clear();
  round_result = queue.new_round(1000, f);
  CAF_CHECK_EQUAL(round_result, make_new_round_result(true));
  CAF_CHECK_EQUAL(f.result, "0:12");
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(priorities) {
  queue.policy().enable_priorities = true;
  fill(queue, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  // Allow f to consume 2 items from the high priority and 1 item otherwise.
  CAF_CHECK_EQUAL(fetch(1), "0:3,0:6,1:1,2:2");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Drain the high-priority queue with one item left per other queue.
  CAF_CHECK_EQUAL(fetch(1), "0:9,1:4,2:5");
  CAF_REQUIRE_EQUAL(queue.empty(), false);
  // Drain queue.
  CAF_CHECK_EQUAL(fetch(1000), "1:7,2:8");
  CAF_REQUIRE_EQUAL(queue.empty(), true);
}

CAF_TEST(peek_all) {
  auto queue_to_string = [&] {
    std::string str;
    auto peek_fun = [&](const inode& x) {
      if (!str.empty())
        str += ", ";
      str += std::to_string(x.value);
    };
    queue.peek_all(peek_fun);
    return str;
  };
  CAF_CHECK_EQUAL(queue_to_string(), "");
  queue.emplace_back(1);
  CAF_CHECK_EQUAL(queue_to_string(), "1");
  queue.emplace_back(2);
  CAF_CHECK_EQUAL(queue_to_string(), "1, 2");
  queue.emplace_back(3);
  // Lists are iterated in order and 3 is stored in the first queue for
  // `x mod 3 == 0` values.
  CAF_CHECK_EQUAL(queue_to_string(), "3, 1, 2");
  queue.emplace_back(4);
  CAF_CHECK_EQUAL(queue_to_string(), "3, 1, 4, 2");
}

CAF_TEST(to_string) {
  CAF_CHECK_EQUAL(deep_to_string(queue), "[]");
  fill(queue, 1, 2, 3, 4);
  CAF_CHECK_EQUAL(deep_to_string(queue), "[3, 1, 4, 2]");
}

CAF_TEST_FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <v8.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#include <telldus-core.h>

using namespace v8;
using namespace node;
using namespace std;

namespace telldus_v8 {

    struct DeviceEventBatton {
        Persistent<Function> callback;
        int deviceId;
    };

    struct SensorEventBatton {
        Persistent<Function> callback;
        int sensorId;
        const char *model;
        const char *protocol;
        const char *value;
        int ts;
        int dataType;
    };

    struct RawDeviceEventBatton {
        Persistent<Function> callback;
        int controllerId;
        const char *data;
    };

    const int SUPPORTED_METHODS =
    TELLSTICK_TURNON
    | TELLSTICK_TURNOFF
    | TELLSTICK_BELL
    | TELLSTICK_TOGGLE
    | TELLSTICK_DIM
    | TELLSTICK_LEARN
    | TELLSTICK_EXECUTE
    | TELLSTICK_UP
    | TELLSTICK_DOWN
    | TELLSTICK_STOP;

    Handle<Value> getNumberOfDevices( const Arguments& args ) {
        HandleScope scope;
        //tdInit();
        Local<Number> num = Number::New(tdGetNumberOfDevices());
        return scope.Close(num);
    }

    Local<Object> GetSuportedMethods(int id){

        int methods = tdMethods( id, SUPPORTED_METHODS );
        Local<Array> methodsObj = Array::New();
        int i = 0;
        if (methods & TELLSTICK_TURNON)
        {
            methodsObj->Set(i++, String::New("TURNON"));
        }
        if (methods & TELLSTICK_TURNOFF)
        {
            methodsObj->Set(i++, String::New("TURNOFF"));
        }
        if (methods & TELLSTICK_BELL)
        {
            methodsObj->Set(i++, String::New("BELL"));
        }
        if (methods & TELLSTICK_TOGGLE)
        {
            methodsObj->Set(i++, String::New("TOGGLE"));
        }
        if (methods & TELLSTICK_DIM)
        {
            methodsObj->Set(i++, String::New("DIM"));
        }
        if (methods & TELLSTICK_UP)
        {
            methodsObj->Set(i++, String::New("UP"));
        }
        if (methods & TELLSTICK_DOWN)
        {
            methodsObj->Set(i++, String::New("DOWN"));
        }
        if (methods & TELLSTICK_STOP)
        {
            methodsObj->Set(i++, String::New("STOP"));
        }

        return methodsObj;

    }

    Local<String> GetDeviceType(int id){
        int type = tdGetDeviceType(id);

        if(type & TELLSTICK_TYPE_DEVICE){
            return String::New("DEVICE");
        }

        if(type & TELLSTICK_TYPE_GROUP){
            return String::New("GROUP");
        }

        if(type & TELLSTICK_TYPE_SCENE){
            return String::New("SCENE");
        }
        return String::New("UNKNOWN");
    }

    Local<Object> GetDeviceStatus(int id){
        Local<Object> status = Object::New();
        int lastSentCommand = tdLastSentCommand(id, SUPPORTED_METHODS);
        char *level = 0;
        switch(lastSentCommand) {
            case TELLSTICK_TURNON:
                status->Set(String::NewSymbol("status"), String::New("ON"));
                break;
            case TELLSTICK_TURNOFF:
                status->Set(String::NewSymbol("status"), String::New("OFF"));
                break;
            case TELLSTICK_DIM:
                status->Set(String::NewSymbol("status"), String::New("DIM"));
                level = tdLastSentValue(id);
                status->Set(String::NewSymbol("level"), String::New(level, strlen(level)));
                tdReleaseString(level);
                break;
            default:
                status->Set(String::NewSymbol("status"), String::New("UNNKOWN"));
        }

        return status;
    }

    Local<Object> GetDevice(int index) {

        int id = tdGetDeviceId( index );
        char *name = tdGetName( id );
        char *model = tdGetModel(id);

        Local<Object> obj = Object::New();
        obj->Set(String::NewSymbol("name"), String::New(name, strlen(name)));
        obj->Set(String::NewSymbol("id"), Number::New(id));
        obj->Set(String::NewSymbol("methods"), GetSuportedMethods(id));
        obj->Set(String::NewSymbol("model"), String::New(model, strlen(model)));
        obj->Set(String::NewSymbol("type"), GetDeviceType(id));
        obj->Set(String::NewSymbol("status"), GetDeviceStatus(id));

        tdReleaseString(name);
        tdReleaseString(model);

        return obj;
    }

    Handle<Value> getDevices( const Arguments& args ) {
        HandleScope scope;
        tdInit();

        int intNumberOfDevices = tdGetNumberOfDevices();
        Local<Array> devices = Array::New(intNumberOfDevices);

        for (int i = 0; i < intNumberOfDevices; i++) {
           devices->Set(i, GetDevice(i));
         }

        return scope.Close(devices);
    }

    Handle<Value> turnOn( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdTurnOn(args[0]->NumberValue()));
        return scope.Close(num);
    }

    Handle<Value> turnOff( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdTurnOff(args[0]->NumberValue()));
        return scope.Close(num);
    }

    Handle<Value> dim( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()|| !args[1]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdDim(args[0]->NumberValue(),(unsigned char)args[1]->NumberValue() ));
        return scope.Close(num);
    }

    int DeviceEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        DeviceEventBatton *batton = static_cast<DeviceEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->deviceId),
            GetDeviceStatus(batton->deviceId),
        };

        batton->callback->Call(batton->callback, 3, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void DeviceEventCallback( int deviceId, int method, const char * data, int callbackId, void* callbackVoid ) {
        DeviceEventBatton *batton = new DeviceEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->deviceId = deviceId;
        eio_nop(EIO_PRI_DEFAULT, DeviceEventCallbackAfter, batton);
    }

    Handle<Value> addDeviceEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterDeviceEvent(&DeviceEventCallback, *callback));
        return scope.Close(num);
    }

    int SensorEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        SensorEventBatton *batton = static_cast<SensorEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->sensorId),
            String::New(batton->model),
            String::New(batton->protocol),
            Number::New(batton->dataType),
            String::New(batton->value),
            Number::New(batton->ts)
        };

        batton->callback->Call(batton->callback, 6, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void SensorEventCallback( const char *protocol, const char *model, int sensorId, int dataType, const char *value,
            int ts, int callbackId, void *callbackVoid ) {

        SensorEventBatton *batton = new SensorEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->sensorId = sensorId;
        batton->protocol = protocol;
        batton->model = model;
        batton->ts = ts;
        batton->dataType = dataType;
        batton->value = value;

        eio_nop(EIO_PRI_DEFAULT, SensorEventCallbackAfter, batton);
    }

    Handle<Value> addSensorEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterSensorEvent(&SensorEventCallback, *callback));
        return scope.Close(num);
    }

    int RawDataEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        RawDeviceEventBatton *batton = static_cast<RawDeviceEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->controllerId),
            String::New(batton->data),
        };

        batton->callback->Call(batton->callback, 5, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void RawDataCallback(const char* data, int controllerId, int callbackId, void *callbackVoid) {
        RawDeviceEventBatton *batton = new RawDeviceEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->data = data;
        batton->controllerId = controllerId;
        eio_nop(EIO_PRI_DEFAULT, RawDataEventCallbackAfter, batton);
    }

    Handle<Value> addRawDeviceEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterRawDeviceEvent(&RawDataCallback, *callback));
        return scope.Close(num);
    }

    Handle<Value> removeEventListener( const Arguments &args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (int callbackId)")));
        }
        tdUnregisterCallback(args[0]->ToInteger()->Value());

        //FIXME: Fix leak of callback.

        return scope.Close(Undefined());
    }
}

extern "C"
void init(Handle<Object> target) {

    HandleScope scope;
    target->Set(String::NewSymbol("getNumberOfDevices"),
      FunctionTemplate::New(telldus_v8::getNumberOfDevices)->GetFunction());
    target->Set(String::NewSymbol("getDevices"),
      FunctionTemplate::New(telldus_v8::getDevices)->GetFunction());
    target->Set(String::NewSymbol("turnOn"),
      FunctionTemplate::New(telldus_v8::turnOn)->GetFunction());
    target->Set(String::NewSymbol("turnOff"),
      FunctionTemplate::New(telldus_v8::turnOff)->GetFunction());
    target->Set(String::NewSymbol("dim"),
      FunctionTemplate::New(telldus_v8::dim)->GetFunction());
    target->Set(String::NewSymbol("addDeviceEventListener"),
      FunctionTemplate::New(telldus_v8::addDeviceEventListener)->GetFunction());
    target->Set(String::NewSymbol("addSensorEventListener"),
      FunctionTemplate::New(telldus_v8::addSensorEventListener)->GetFunction());
    target->Set(String::NewSymbol("addRawDeviceEventListener"),
      FunctionTemplate::New(telldus_v8::addRawDeviceEventListener)->GetFunction());
    target->Set(String::NewSymbol("removeEventListener"),
      FunctionTemplate::New(telldus_v8::removeEventListener)->GetFunction());
}

NODE_MODULE(telldus, init)
<commit_msg>fixed build warning<commit_after>#ifndef BUILDING_NODE_EXTENSION
#define BUILDING_NODE_EXTENSION
#endif

#include <node.h>
#include <v8.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#include <telldus-core.h>

using namespace v8;
using namespace node;
using namespace std;

namespace telldus_v8 {

    struct DeviceEventBatton {
        Persistent<Function> callback;
        int deviceId;
    };

    struct SensorEventBatton {
        Persistent<Function> callback;
        int sensorId;
        const char *model;
        const char *protocol;
        const char *value;
        int ts;
        int dataType;
    };

    struct RawDeviceEventBatton {
        Persistent<Function> callback;
        int controllerId;
        const char *data;
    };

    const int SUPPORTED_METHODS =
    TELLSTICK_TURNON
    | TELLSTICK_TURNOFF
    | TELLSTICK_BELL
    | TELLSTICK_TOGGLE
    | TELLSTICK_DIM
    | TELLSTICK_LEARN
    | TELLSTICK_EXECUTE
    | TELLSTICK_UP
    | TELLSTICK_DOWN
    | TELLSTICK_STOP;

    Handle<Value> getNumberOfDevices( const Arguments& args ) {
        HandleScope scope;
        //tdInit();
        Local<Number> num = Number::New(tdGetNumberOfDevices());
        return scope.Close(num);
    }

    Local<Object> GetSuportedMethods(int id){

        int methods = tdMethods( id, SUPPORTED_METHODS );
        Local<Array> methodsObj = Array::New();
        int i = 0;
        if (methods & TELLSTICK_TURNON)
        {
            methodsObj->Set(i++, String::New("TURNON"));
        }
        if (methods & TELLSTICK_TURNOFF)
        {
            methodsObj->Set(i++, String::New("TURNOFF"));
        }
        if (methods & TELLSTICK_BELL)
        {
            methodsObj->Set(i++, String::New("BELL"));
        }
        if (methods & TELLSTICK_TOGGLE)
        {
            methodsObj->Set(i++, String::New("TOGGLE"));
        }
        if (methods & TELLSTICK_DIM)
        {
            methodsObj->Set(i++, String::New("DIM"));
        }
        if (methods & TELLSTICK_UP)
        {
            methodsObj->Set(i++, String::New("UP"));
        }
        if (methods & TELLSTICK_DOWN)
        {
            methodsObj->Set(i++, String::New("DOWN"));
        }
        if (methods & TELLSTICK_STOP)
        {
            methodsObj->Set(i++, String::New("STOP"));
        }

        return methodsObj;

    }

    Local<String> GetDeviceType(int id){
        int type = tdGetDeviceType(id);

        if(type & TELLSTICK_TYPE_DEVICE){
            return String::New("DEVICE");
        }

        if(type & TELLSTICK_TYPE_GROUP){
            return String::New("GROUP");
        }

        if(type & TELLSTICK_TYPE_SCENE){
            return String::New("SCENE");
        }
        return String::New("UNKNOWN");
    }

    Local<Object> GetDeviceStatus(int id){
        Local<Object> status = Object::New();
        int lastSentCommand = tdLastSentCommand(id, SUPPORTED_METHODS);
        char *level = 0;
        switch(lastSentCommand) {
            case TELLSTICK_TURNON:
                status->Set(String::NewSymbol("status"), String::New("ON"));
                break;
            case TELLSTICK_TURNOFF:
                status->Set(String::NewSymbol("status"), String::New("OFF"));
                break;
            case TELLSTICK_DIM:
                status->Set(String::NewSymbol("status"), String::New("DIM"));
                level = tdLastSentValue(id);
                status->Set(String::NewSymbol("level"), String::New(level, strlen(level)));
                tdReleaseString(level);
                break;
            default:
                status->Set(String::NewSymbol("status"), String::New("UNNKOWN"));
        }

        return status;
    }

    Local<Object> GetDevice(int index) {

        int id = tdGetDeviceId( index );
        char *name = tdGetName( id );
        char *model = tdGetModel(id);

        Local<Object> obj = Object::New();
        obj->Set(String::NewSymbol("name"), String::New(name, strlen(name)));
        obj->Set(String::NewSymbol("id"), Number::New(id));
        obj->Set(String::NewSymbol("methods"), GetSuportedMethods(id));
        obj->Set(String::NewSymbol("model"), String::New(model, strlen(model)));
        obj->Set(String::NewSymbol("type"), GetDeviceType(id));
        obj->Set(String::NewSymbol("status"), GetDeviceStatus(id));

        tdReleaseString(name);
        tdReleaseString(model);

        return obj;
    }

    Handle<Value> getDevices( const Arguments& args ) {
        HandleScope scope;
        tdInit();

        int intNumberOfDevices = tdGetNumberOfDevices();
        Local<Array> devices = Array::New(intNumberOfDevices);

        for (int i = 0; i < intNumberOfDevices; i++) {
           devices->Set(i, GetDevice(i));
         }

        return scope.Close(devices);
    }

    Handle<Value> turnOn( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdTurnOn(args[0]->NumberValue()));
        return scope.Close(num);
    }

    Handle<Value> turnOff( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdTurnOff(args[0]->NumberValue()));
        return scope.Close(num);
    }

    Handle<Value> dim( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()|| !args[1]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Wrong arguments")));
        }

        Local<Number> num = Number::New(tdDim(args[0]->NumberValue(),(unsigned char)args[1]->NumberValue() ));
        return scope.Close(num);
    }

    int DeviceEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        DeviceEventBatton *batton = static_cast<DeviceEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->deviceId),
            GetDeviceStatus(batton->deviceId),
        };

        batton->callback->Call(batton->callback, 3, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void DeviceEventCallback( int deviceId, int method, const char * data, int callbackId, void* callbackVoid ) {
        DeviceEventBatton *batton = new DeviceEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->deviceId = deviceId;
        eio_nop(EIO_PRI_DEFAULT, DeviceEventCallbackAfter, batton);
    }

    Handle<Value> addDeviceEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterDeviceEvent(&DeviceEventCallback, *callback));
        return scope.Close(num);
    }

    int SensorEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        SensorEventBatton *batton = static_cast<SensorEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->sensorId),
            String::New(batton->model),
            String::New(batton->protocol),
            Number::New(batton->dataType),
            String::New(batton->value),
            Number::New(batton->ts)
        };

        batton->callback->Call(batton->callback, 6, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void SensorEventCallback( const char *protocol, const char *model, int sensorId, int dataType, const char *value,
            int ts, int callbackId, void *callbackVoid ) {

        SensorEventBatton *batton = new SensorEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->sensorId = sensorId;
        batton->protocol = protocol;
        batton->model = model;
        batton->ts = ts;
        batton->dataType = dataType;
        batton->value = value;

        eio_nop(EIO_PRI_DEFAULT, SensorEventCallbackAfter, batton);
    }

    Handle<Value> addSensorEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterSensorEvent(&SensorEventCallback, *callback));
        return scope.Close(num);
    }

    int RawDataEventCallbackAfter(eio_req *req) {
        HandleScope scope;
        RawDeviceEventBatton *batton = static_cast<RawDeviceEventBatton *>(req->data);

        Local<Value> args[] = {
            Number::New(batton->controllerId),
            String::New(batton->data),
        };

        batton->callback->Call(batton->callback, 5, args);
        scope.Close(Undefined());

        delete batton;
        return 0;
    }

    void RawDataCallback(const char* data, int controllerId, int callbackId, void *callbackVoid) {
        RawDeviceEventBatton *batton = new RawDeviceEventBatton();
        batton->callback = static_cast<Function *>(callbackVoid);
        batton->data = data;
        batton->controllerId = controllerId;
        eio_nop(EIO_PRI_DEFAULT, RawDataEventCallbackAfter, batton);
    }

    Handle<Value> addRawDeviceEventListener( const Arguments& args ) {
        HandleScope scope;
        if (!args[0]->IsFunction()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (function callback)")));
        }

        Persistent<Function> callback = Persistent<Function>::New(Handle<Function>::Cast(args[0]));
        Local<Number> num = Number::New(tdRegisterRawDeviceEvent(&RawDataCallback, *callback));
        return scope.Close(num);
    }

    Handle<Value> removeEventListener( const Arguments &args ) {
        HandleScope scope;
        if (!args[0]->IsNumber()) {
            return ThrowException(Exception::TypeError(String::New("Expected 1 argument: (int callbackId)")));
        }
        tdUnregisterCallback(args[0]->ToInteger()->Value());

        //FIXME: Fix leak of callback.

        return scope.Close(Undefined());
    }
}

extern "C"
void init(Handle<Object> target) {

    HandleScope scope;
    target->Set(String::NewSymbol("getNumberOfDevices"),
      FunctionTemplate::New(telldus_v8::getNumberOfDevices)->GetFunction());
    target->Set(String::NewSymbol("getDevices"),
      FunctionTemplate::New(telldus_v8::getDevices)->GetFunction());
    target->Set(String::NewSymbol("turnOn"),
      FunctionTemplate::New(telldus_v8::turnOn)->GetFunction());
    target->Set(String::NewSymbol("turnOff"),
      FunctionTemplate::New(telldus_v8::turnOff)->GetFunction());
    target->Set(String::NewSymbol("dim"),
      FunctionTemplate::New(telldus_v8::dim)->GetFunction());
    target->Set(String::NewSymbol("addDeviceEventListener"),
      FunctionTemplate::New(telldus_v8::addDeviceEventListener)->GetFunction());
    target->Set(String::NewSymbol("addSensorEventListener"),
      FunctionTemplate::New(telldus_v8::addSensorEventListener)->GetFunction());
    target->Set(String::NewSymbol("addRawDeviceEventListener"),
      FunctionTemplate::New(telldus_v8::addRawDeviceEventListener)->GetFunction());
    target->Set(String::NewSymbol("removeEventListener"),
      FunctionTemplate::New(telldus_v8::removeEventListener)->GetFunction());
}

NODE_MODULE(telldus, init)
<|endoftext|>