<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * Copyright (C) 2002-2022 Németh László
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks.
 *
 * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno,
 * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád,
 * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter,
 * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls,
 * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
/*
 * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada
 * And Contributors.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. All modifications to the source code must be clearly marked as
 *    such.  Binary redistributions based on modified source code
 *    must be clearly marked as modified versions in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <limits>

#include "replist.hxx"
#include "csutil.hxx"

RepList::RepList(int n) {
  dat.reserve(n);
}

RepList::~RepList() {
  for (size_t i = 0, pos = dat.size(); i < pos; ++i) {
    delete dat[i];
  }
}

int RepList::find(const char* word) {
  int p1 = 0;
  int p2 = dat.size() - 1;
  int ret = -1;
  while (p1 <= p2) {
    int m = ((unsigned)p1 + (unsigned)p2) >> 1;
    int c = strncmp(word, dat[m]->pattern.c_str(), dat[m]->pattern.size());
    if (c < 0)
      p2 = m - 1;
    else if (c > 0)
      p1 = m + 1;
    else {      // scan in the right half for a longer match
      ret = m;
      p1 = m + 1;
    }
  }
  return ret;
}

std::string RepList::replace(const size_t wordlen, int ind, bool atstart) {
  int type = atstart ? 1 : 0;
  if (ind < 0)
    return std::string();
  if (wordlen == dat[ind]->pattern.size())
    type = atstart ? 3 : 2;
  while (type && dat[ind]->outstrings[type].empty())
    type = (type == 2 && !atstart) ? 0 : type - 1;
  return dat[ind]->outstrings[type];
}

int RepList::add(const std::string& in_pat1, const std::string& pat2) {
  if (in_pat1.empty() || pat2.empty()) {
    return 1;
  }
  // analyse word context
  int type = 0;
  std::string pat1(in_pat1);
  if (pat1[0] == '_') {
    pat1.erase(0, 1);
    type = 1;
  }
  if (!pat1.empty() && pat1[pat1.size() - 1] == '_') {
    type = type + 2;
    pat1.erase(pat1.size() - 1);
  }
  mystrrep(pat1, "_", " ");

  // find existing entry
  int m = find(pat1.c_str());
  if (m >= 0 && dat[m]->pattern == pat1) {
    // since already used
    dat[m]->outstrings[type] = pat2;
    mystrrep(dat[m]->outstrings[type], "_", " ");
    return 0;
  }

  // make a new entry if none exists
  replentry* r = new replentry;
  if (r == NULL)
    return 1;
  r->pattern = pat1;
  r->outstrings[type] = pat2;
  mystrrep(r->outstrings[type], "_", " ");
  dat.push_back(r);
  // sort to the right place in the list
  size_t i;
  for (i = dat.size() - 1; i > 0; --i) {
    if (strcmp(r->pattern.c_str(), dat[i - 1]->pattern.c_str()) < 0) {
      dat[i] = dat[i - 1];
    } else
      break;
  }
  dat[i] = r;
  return 0;
}

bool RepList::conv(const std::string& in_word, std::string& dest) {
  dest.clear();

  size_t wordlen = in_word.size();
  const char* word = in_word.c_str();

  bool change = false;
  for (size_t i = 0; i < wordlen; ++i) {
    int n = find(word + i);
    std::string l = replace(wordlen - i, n, i == 0);
    if (!l.empty()) {
      dest.append(l);
      i += dat[n]->pattern.size() - 1;
      change = true;
    } else {
      dest.push_back(word[i]);
    }
  }

  return change;
}

<commit_msg>cid#398998 Argument cannot be negative<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * Copyright (C) 2002-2022 Németh László
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Hunspell is based on MySpell which is Copyright (C) 2002 Kevin Hendricks.
 *
 * Contributor(s): David Einstein, Davide Prina, Giuseppe Modugno,
 * Gianluca Turconi, Simon Brouwer, Noll János, Bíró Árpád,
 * Goldman Eleonóra, Sarlós Tamás, Bencsáth Boldizsár, Halácsy Péter,
 * Dvornik László, Gefferth András, Nagy Viktor, Varga Dániel, Chris Halls,
 * Rene Engelhard, Bram Moolenaar, Dafydd Jones, Harri Pitkänen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
/*
 * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada
 * And Contributors.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. All modifications to the source code must be clearly marked as
 *    such.  Binary redistributions based on modified source code
 *    must be clearly marked as modified versions in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <limits>

#include "replist.hxx"
#include "csutil.hxx"

RepList::RepList(int n) {
  dat.reserve(n);
}

RepList::~RepList() {
  for (size_t i = 0, pos = dat.size(); i < pos; ++i) {
    delete dat[i];
  }
}

int RepList::find(const char* word) {
  int p1 = 0;
  int p2 = dat.size() - 1;
  int ret = -1;
  while (p1 <= p2) {
    int m = ((unsigned)p1 + (unsigned)p2) >> 1;
    int c = strncmp(word, dat[m]->pattern.c_str(), dat[m]->pattern.size());
    if (c < 0)
      p2 = m - 1;
    else if (c > 0)
      p1 = m + 1;
    else {      // scan in the right half for a longer match
      ret = m;
      p1 = m + 1;
    }
  }
  return ret;
}

std::string RepList::replace(const size_t wordlen, int ind, bool atstart) {
  int type = atstart ? 1 : 0;
  if (wordlen == dat[ind]->pattern.size())
    type = atstart ? 3 : 2;
  while (type && dat[ind]->outstrings[type].empty())
    type = (type == 2 && !atstart) ? 0 : type - 1;
  return dat[ind]->outstrings[type];
}

int RepList::add(const std::string& in_pat1, const std::string& pat2) {
  if (in_pat1.empty() || pat2.empty()) {
    return 1;
  }
  // analyse word context
  int type = 0;
  std::string pat1(in_pat1);
  if (pat1[0] == '_') {
    pat1.erase(0, 1);
    type = 1;
  }
  if (!pat1.empty() && pat1[pat1.size() - 1] == '_') {
    type = type + 2;
    pat1.erase(pat1.size() - 1);
  }
  mystrrep(pat1, "_", " ");

  // find existing entry
  int m = find(pat1.c_str());
  if (m >= 0 && dat[m]->pattern == pat1) {
    // since already used
    dat[m]->outstrings[type] = pat2;
    mystrrep(dat[m]->outstrings[type], "_", " ");
    return 0;
  }

  // make a new entry if none exists
  replentry* r = new replentry;
  if (r == NULL)
    return 1;
  r->pattern = pat1;
  r->outstrings[type] = pat2;
  mystrrep(r->outstrings[type], "_", " ");
  dat.push_back(r);
  // sort to the right place in the list
  size_t i;
  for (i = dat.size() - 1; i > 0; --i) {
    if (strcmp(r->pattern.c_str(), dat[i - 1]->pattern.c_str()) < 0) {
      dat[i] = dat[i - 1];
    } else
      break;
  }
  dat[i] = r;
  return 0;
}

bool RepList::conv(const std::string& in_word, std::string& dest) {
  dest.clear();

  size_t wordlen = in_word.size();
  const char* word = in_word.c_str();

  bool change = false;
  for (size_t i = 0; i < wordlen; ++i) {
    int n = find(word + i);

    bool empty = n < 0;
    if (empty) {
      dest.push_back(word[i]);
      continue;
    }

    std::string l = replace(wordlen - i, n, i == 0);
    if (l.empty()) {
      dest.push_back(word[i]);
      continue;
    }

    dest.append(l);
    i += dat[n]->pattern.size() - 1;
    change = true;
  }

  return change;
}

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// order_by_executor.cpp
//
// Identification: src/backend/executor/order_by_executor.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/common/logger.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/executor/order_by_executor.h"

#include "../planner/order_by_plan.h"
#include "backend/storage/tile.h"

namespace peloton {
namespace executor {

/**
 * @brief Constructor
 * @param node  OrderByNode plan node corresponding to this executor
 */
OrderByExecutor::OrderByExecutor(const planner::AbstractPlan *node,
                                 ExecutorContext *executor_context)
    : AbstractExecutor(node, executor_context) {}

bool OrderByExecutor::DInit() {
  assert(children_.size() == 1);

  sort_done_ = false;
  num_tuples_returned_ = 0;

  return true;
}

bool OrderByExecutor::DExecute() {
  LOG_TRACE("Order By executor \n");

  if (!sort_done_) DoSort();

  if (!(num_tuples_returned_ < sort_buffer_.size())) {
    return false;
  }

  assert(sort_done_);
  assert(input_schema_.get());
  assert(input_tiles_.size() > 0);

  // Grab data from plan node
  const planner::OrderByPlan &node = GetPlanNode<planner::OrderByPlan>();

  // Returned tiles must be newly created physical tiles,
  // which have the same physical schema as input tiles.
  size_t tile_size = std::min(size_t(DEFAULT_TUPLES_PER_TILEGROUP),
                              sort_buffer_.size() - num_tuples_returned_);
  storage::Tile *ptile = storage::TileFactory::GetTile(
      INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID, nullptr,
      *input_schema_, nullptr, tile_size);
  for (size_t id = 0; id < tile_size; id++) {
    oid_t source_tile_id =
        sort_buffer_[num_tuples_returned_ + id].item_pointer.block;
    oid_t source_tuple_id =
        sort_buffer_[num_tuples_returned_ + id].item_pointer.offset;
    // Insert a physical tuple into physical tile
    for (oid_t col = 0; col < input_schema_->GetColumnCount(); col++) {
      ptile->SetValue(
          input_tiles_[source_tile_id]->GetValue(source_tuple_id, col), id,
          col);
    }
  }

  // Create an owner wrapper of this physical tile
  std::vector<storage::Tile *> singleton({ptile});
  std::unique_ptr<LogicalTile> ltile(
      LogicalTileFactory::WrapTiles(singleton));
  assert(ltile->GetTupleCount() == tile_size);

  SetOutput(ltile.release());

  num_tuples_returned_ += tile_size;

  assert(num_tuples_returned_ <= sort_buffer_.size());

  return true;
}

bool OrderByExecutor::DoSort() {
  assert(children_.size() == 1);
  assert(children_[0] != nullptr);
  assert(!sort_done_);

  // Extract all data from child
  while (children_[0]->Execute()) {
    input_tiles_.emplace_back(children_[0]->GetOutput());
  }

  /** Number of valid tuples to be sorted. */
  size_t count = 0;
  for (auto &tile : input_tiles_) {
    count += tile->GetTupleCount();
  }

  if (count == 0) return true;

  // Grab data from plan node
  const planner::OrderByPlan &node = GetPlanNode<planner::OrderByPlan>();
  descend_flags_ = node.GetDescendFlags();

  // Extract the schema for sort keys.
  input_schema_.reset(input_tiles_[0]->GetPhysicalSchema());
  std::vector<catalog::Column> sort_key_columns;
  for (auto id : node.GetSortKeys()) {
    sort_key_columns.push_back(input_schema_->GetColumn(id));
  }
  sort_key_tuple_schema_.reset(new catalog::Schema(sort_key_columns));

  // Extract all valid tuples into a single std::vector (the sort buffer)
  sort_buffer_.reserve(count);
  for (oid_t tile_id = 0; tile_id < input_tiles_.size(); tile_id++) {
    for (oid_t tuple_id : *input_tiles_[tile_id]) {
      // Extract the sort key tuple
      std::unique_ptr<storage::Tuple> tuple(
          new storage::Tuple(sort_key_tuple_schema_.get(), true));
      for (oid_t id = 0; id < node.GetSortKeys().size(); id++) {
        tuple->SetValue(id, input_tiles_[tile_id]->GetValue(
                                tuple_id, node.GetSortKeys()[id]));
      }
      // Inert the sort key tuple into sort buffer
      sort_buffer_.emplace_back(sort_buffer_entry_t(
          ItemPointer(tile_id, tuple_id), std::move(tuple)));
    }
  }

  assert(count == sort_buffer_.size());

  // Prepare the compare function
  // Note: This is a less-than comparer, NOT an equality comparer.
  struct TupleComparer {
    TupleComparer(std::vector<bool> &_descend_flags)
        : descend_flags(_descend_flags) {}

    bool operator()(const storage::Tuple *ta, const storage::Tuple *tb) {
      for (oid_t id = 0; id < descend_flags.size(); id++) {
        if (!descend_flags[id]) {
          if (ta->GetValue(id).OpLessThan(tb->GetValue(id)).IsTrue()) {
            return true;
          } else if (ta->GetValue(id)
                         .OpGreaterThan(tb->GetValue(id))
                         .IsTrue()) {
            return false;
          }
        } else {
          if (tb->GetValue(id).OpLessThan(ta->GetValue(id)).IsTrue()) {
            return true;
          } else if (tb->GetValue(id)
                         .OpGreaterThan(ta->GetValue(id))
                         .IsTrue()) {
            return false;
          }
        }
      }
      return false;  // Will return false if all keys equal
    }

    std::vector<bool> descend_flags;
  };

  TupleComparer comp(descend_flags_);

  // Finally ... sort it !
  std::sort(
      sort_buffer_.begin(), sort_buffer_.end(),
      [&comp](const sort_buffer_entry_t &a, const sort_buffer_entry_t &b) {
        return comp(a.tuple.get(), b.tuple.get());
      });

  sort_done_ = true;

  return true;
}

} /* namespace executor */
} /* namespace peloton */
<commit_msg>Minor fix<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// order_by_executor.cpp
//
// Identification: src/backend/executor/order_by_executor.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/common/logger.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/logical_tile_factory.h"
#include "backend/executor/order_by_executor.h"

#include "../planner/order_by_plan.h"
#include "backend/storage/tile.h"

namespace peloton {
namespace executor {

/**
 * @brief Constructor
 * @param node  OrderByNode plan node corresponding to this executor
 */
OrderByExecutor::OrderByExecutor(const planner::AbstractPlan *node,
                                 ExecutorContext *executor_context)
    : AbstractExecutor(node, executor_context) {}

bool OrderByExecutor::DInit() {
  assert(children_.size() == 1);

  sort_done_ = false;
  num_tuples_returned_ = 0;

  return true;
}

bool OrderByExecutor::DExecute() {
  LOG_TRACE("Order By executor \n");

  if (!sort_done_) DoSort();

  if (!(num_tuples_returned_ < sort_buffer_.size())) {
    return false;
  }

  assert(sort_done_);
  assert(input_schema_.get());
  assert(input_tiles_.size() > 0);

  // Returned tiles must be newly created physical tiles,
  // which have the same physical schema as input tiles.
  size_t tile_size = std::min(size_t(DEFAULT_TUPLES_PER_TILEGROUP),
                              sort_buffer_.size() - num_tuples_returned_);
  storage::Tile *ptile = storage::TileFactory::GetTile(
      INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID, nullptr,
      *input_schema_, nullptr, tile_size);
  for (size_t id = 0; id < tile_size; id++) {
    oid_t source_tile_id =
        sort_buffer_[num_tuples_returned_ + id].item_pointer.block;
    oid_t source_tuple_id =
        sort_buffer_[num_tuples_returned_ + id].item_pointer.offset;
    // Insert a physical tuple into physical tile
    for (oid_t col = 0; col < input_schema_->GetColumnCount(); col++) {
      ptile->SetValue(
          input_tiles_[source_tile_id]->GetValue(source_tuple_id, col), id,
          col);
    }
  }

  // Create an owner wrapper of this physical tile
  std::vector<storage::Tile *> singleton({ptile});
  std::unique_ptr<LogicalTile> ltile(
      LogicalTileFactory::WrapTiles(singleton));
  assert(ltile->GetTupleCount() == tile_size);

  SetOutput(ltile.release());

  num_tuples_returned_ += tile_size;

  assert(num_tuples_returned_ <= sort_buffer_.size());

  return true;
}

bool OrderByExecutor::DoSort() {
  assert(children_.size() == 1);
  assert(children_[0] != nullptr);
  assert(!sort_done_);

  // Extract all data from child
  while (children_[0]->Execute()) {
    input_tiles_.emplace_back(children_[0]->GetOutput());
  }

  /** Number of valid tuples to be sorted. */
  size_t count = 0;
  for (auto &tile : input_tiles_) {
    count += tile->GetTupleCount();
  }

  if (count == 0) return true;

  // Grab data from plan node
  const planner::OrderByPlan &node = GetPlanNode<planner::OrderByPlan>();
  descend_flags_ = node.GetDescendFlags();

  // Extract the schema for sort keys.
  input_schema_.reset(input_tiles_[0]->GetPhysicalSchema());
  std::vector<catalog::Column> sort_key_columns;
  for (auto id : node.GetSortKeys()) {
    sort_key_columns.push_back(input_schema_->GetColumn(id));
  }
  sort_key_tuple_schema_.reset(new catalog::Schema(sort_key_columns));

  // Extract all valid tuples into a single std::vector (the sort buffer)
  sort_buffer_.reserve(count);
  for (oid_t tile_id = 0; tile_id < input_tiles_.size(); tile_id++) {
    for (oid_t tuple_id : *input_tiles_[tile_id]) {
      // Extract the sort key tuple
      std::unique_ptr<storage::Tuple> tuple(
          new storage::Tuple(sort_key_tuple_schema_.get(), true));
      for (oid_t id = 0; id < node.GetSortKeys().size(); id++) {
        tuple->SetValue(id, input_tiles_[tile_id]->GetValue(
                                tuple_id, node.GetSortKeys()[id]));
      }
      // Inert the sort key tuple into sort buffer
      sort_buffer_.emplace_back(sort_buffer_entry_t(
          ItemPointer(tile_id, tuple_id), std::move(tuple)));
    }
  }

  assert(count == sort_buffer_.size());

  // Prepare the compare function
  // Note: This is a less-than comparer, NOT an equality comparer.
  struct TupleComparer {
    TupleComparer(std::vector<bool> &_descend_flags)
        : descend_flags(_descend_flags) {}

    bool operator()(const storage::Tuple *ta, const storage::Tuple *tb) {
      for (oid_t id = 0; id < descend_flags.size(); id++) {
        if (!descend_flags[id]) {
          if (ta->GetValue(id).OpLessThan(tb->GetValue(id)).IsTrue()) {
            return true;
          } else if (ta->GetValue(id)
                         .OpGreaterThan(tb->GetValue(id))
                         .IsTrue()) {
            return false;
          }
        } else {
          if (tb->GetValue(id).OpLessThan(ta->GetValue(id)).IsTrue()) {
            return true;
          } else if (tb->GetValue(id)
                         .OpGreaterThan(ta->GetValue(id))
                         .IsTrue()) {
            return false;
          }
        }
      }
      return false;  // Will return false if all keys equal
    }

    std::vector<bool> descend_flags;
  };

  TupleComparer comp(descend_flags_);

  // Finally ... sort it !
  std::sort(
      sort_buffer_.begin(), sort_buffer_.end(),
      [&comp](const sort_buffer_entry_t &a, const sort_buffer_entry_t &b) {
        return comp(a.tuple.get(), b.tuple.get());
      });

  sort_done_ = true;

  return true;
}

} /* namespace executor */
} /* namespace peloton */
<|endoftext|>


<commit_before>#include <QtTest/QtTest>

#include <TelepathyQt4/Constants>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/CapabilitiesBase>
#include <TelepathyQt4/ConnectionCapabilities>
#include <TelepathyQt4/ContactCapabilities>
#include <TelepathyQt4/Types>

#include <TelepathyQt4/test-backdoors.h>

using namespace Tp;

class TestCapabilities : public QObject
{
    Q_OBJECT

public:
    TestCapabilities(QObject *parent = 0);

private Q_SLOTS:
    void testConnCapabilities();
    void testContactCapabilities();
};

TestCapabilities::TestCapabilities(QObject *parent)
    : QObject(parent)
{
    Tp::enableDebug(true);
    Tp::enableWarnings(true);
}

void TestCapabilities::testConnCapabilities()
{
    ConnectionCapabilities connCaps;
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(!connCaps.textChats());
    QVERIFY(!connCaps.streamedMediaCalls());
    QVERIFY(!connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(!connCaps.upgradingStreamedMediaCalls());
    QVERIFY(!connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());

    RequestableChannelClassSpecList rccSpecs;
    rccSpecs.append(RequestableChannelClassSpec::textChat());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());
    rccSpecs.append(RequestableChannelClassSpec::fileTransfer());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(connCaps.textChats());
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());
    QCOMPARE(connCaps.allClassSpecs(), rccSpecs);

    rccSpecs.append(RequestableChannelClassSpec::textChatroom());
    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChat());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroom());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::contactSearch());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServer());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithLimit());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServerAndLimit());
    rccSpecs.append(RequestableChannelClassSpec::streamTube());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(connCaps.textChats());
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(connCaps.conferenceTextChatrooms());
    QVERIFY(connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(connCaps.contactSearches());
    QVERIFY(connCaps.contactSearchesWithSpecificServer());
    QVERIFY(connCaps.contactSearchesWithLimit());
    QVERIFY(connCaps.contactSearch());
    QVERIFY(connCaps.contactSearchWithSpecificServer());
    QVERIFY(connCaps.contactSearchWithLimit());
    QCOMPARE(connCaps.allClassSpecs(), rccSpecs);

    // start over
    rccSpecs.clear();
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(!connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees());
}

void TestCapabilities::testContactCapabilities()
{
    ContactCapabilities contactCaps;
    // capabilities base
    QVERIFY(!contactCaps.isSpecificToContact());
    QVERIFY(!contactCaps.textChats());
    QVERIFY(!contactCaps.streamedMediaCalls());
    QVERIFY(!contactCaps.streamedMediaAudioCalls());
    QVERIFY(!contactCaps.streamedMediaVideoCalls());
    QVERIFY(!contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(!contactCaps.upgradingStreamedMediaCalls());
    QVERIFY(!contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar")));
    QVERIFY(contactCaps.streamTubeServices().isEmpty());

    RequestableChannelClassSpecList rccSpecs;
    rccSpecs.append(RequestableChannelClassSpec::textChat());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());
    rccSpecs.append(RequestableChannelClassSpec::fileTransfer());

    contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true);
    // capabilities base
    QVERIFY(contactCaps.isSpecificToContact());
    QVERIFY(contactCaps.textChats());
    QVERIFY(contactCaps.streamedMediaCalls());
    QVERIFY(contactCaps.streamedMediaAudioCalls());
    QVERIFY(contactCaps.streamedMediaVideoCalls());
    QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar")));
    QVERIFY(contactCaps.streamTubeServices().isEmpty());
    QCOMPARE(contactCaps.allClassSpecs(), rccSpecs);

    rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-foo")));
    rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-bar")));

    contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true);
    // capabilities base
    QVERIFY(contactCaps.isSpecificToContact());
    QVERIFY(contactCaps.textChats());
    QVERIFY(contactCaps.streamedMediaCalls());
    QVERIFY(contactCaps.streamedMediaAudioCalls());
    QVERIFY(contactCaps.streamedMediaVideoCalls());
    QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(contactCaps.streamTubes(QLatin1String("service-bar")));
    QStringList stubeServices = contactCaps.streamTubeServices();
    stubeServices.sort();
    QStringList expectedSTubeServices;
    expectedSTubeServices << QLatin1String("service-foo") << QLatin1String("service-bar");
    expectedSTubeServices.sort();
    QCOMPARE(stubeServices, expectedSTubeServices);
    QCOMPARE(contactCaps.allClassSpecs(), rccSpecs);
}

QTEST_MAIN(TestCapabilities)

#include "_gen/capabilities.cpp.moc.hpp"
<commit_msg>capabilities test: Add more tests for ConnectionCapabilities::*textChat*.<commit_after>#include <QtTest/QtTest>

#include <TelepathyQt4/Constants>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/CapabilitiesBase>
#include <TelepathyQt4/ConnectionCapabilities>
#include <TelepathyQt4/ContactCapabilities>
#include <TelepathyQt4/Types>

#include <TelepathyQt4/test-backdoors.h>

using namespace Tp;

class TestCapabilities : public QObject
{
    Q_OBJECT

public:
    TestCapabilities(QObject *parent = 0);

private Q_SLOTS:
    void testConnCapabilities();
    void testContactCapabilities();
};

TestCapabilities::TestCapabilities(QObject *parent)
    : QObject(parent)
{
    Tp::enableDebug(true);
    Tp::enableWarnings(true);
}

void TestCapabilities::testConnCapabilities()
{
    ConnectionCapabilities connCaps;
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(!connCaps.textChats());
    QVERIFY(!connCaps.streamedMediaCalls());
    QVERIFY(!connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(!connCaps.upgradingStreamedMediaCalls());
    QVERIFY(!connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());

    RequestableChannelClassSpecList rccSpecs;
    rccSpecs.append(RequestableChannelClassSpec::textChat());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());
    rccSpecs.append(RequestableChannelClassSpec::fileTransfer());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(connCaps.textChats());
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());
    QCOMPARE(connCaps.allClassSpecs(), rccSpecs);

    rccSpecs.append(RequestableChannelClassSpec::textChatroom());
    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChat());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroom());
    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees());
    rccSpecs.append(RequestableChannelClassSpec::contactSearch());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServer());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithLimit());
    rccSpecs.append(RequestableChannelClassSpec::contactSearchWithSpecificServerAndLimit());
    rccSpecs.append(RequestableChannelClassSpec::streamTube());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(!connCaps.isSpecificToContact());
    QVERIFY(connCaps.textChats());
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(connCaps.conferenceTextChatrooms());
    QVERIFY(connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(connCaps.contactSearches());
    QVERIFY(connCaps.contactSearchesWithSpecificServer());
    QVERIFY(connCaps.contactSearchesWithLimit());
    QVERIFY(connCaps.contactSearch());
    QVERIFY(connCaps.contactSearchWithSpecificServer());
    QVERIFY(connCaps.contactSearchWithLimit());
    QCOMPARE(connCaps.allClassSpecs(), rccSpecs);

    // start over
    rccSpecs.clear();
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(!connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(!connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(!connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(!connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCall());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(!connCaps.conferenceStreamedMediaCallsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceStreamedMediaCallWithInvitees());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.streamedMediaCalls());
    QVERIFY(connCaps.streamedMediaAudioCalls());
    QVERIFY(connCaps.streamedMediaVideoCalls());
    QVERIFY(connCaps.streamedMediaVideoCallsWithAudio());
    // conn caps specific
    QVERIFY(connCaps.conferenceStreamedMediaCalls());
    QVERIFY(connCaps.conferenceStreamedMediaCallsWithInvitees());

    // capabilities base
    QVERIFY(!connCaps.textChats());
    QVERIFY(!connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());

    rccSpecs.append(RequestableChannelClassSpec::textChat());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(!connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::textChatroom());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(!connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChat());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(!connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatWithInvitees());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(!connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroom());

    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(connCaps.conferenceTextChatrooms());
    QVERIFY(!connCaps.conferenceTextChatroomsWithInvitees());

    rccSpecs.append(RequestableChannelClassSpec::conferenceTextChatroomWithInvitees());
    connCaps = TestBackdoors::createConnectionCapabilities(rccSpecs);
    // capabilities base
    QVERIFY(connCaps.textChats());
    // conn caps specific
    QVERIFY(connCaps.textChatrooms());
    QVERIFY(connCaps.conferenceTextChats());
    QVERIFY(connCaps.conferenceTextChatsWithInvitees());
    QVERIFY(connCaps.conferenceTextChatrooms());
    QVERIFY(connCaps.conferenceTextChatroomsWithInvitees());

    // capabilities base
    QVERIFY(!connCaps.fileTransfers());
    // conn caps specific
    QVERIFY(!connCaps.contactSearches());
    QVERIFY(!connCaps.contactSearchesWithSpecificServer());
    QVERIFY(!connCaps.contactSearchesWithLimit());
    QVERIFY(!connCaps.contactSearch());
    QVERIFY(!connCaps.contactSearchWithSpecificServer());
    QVERIFY(!connCaps.contactSearchWithLimit());
    QVERIFY(!connCaps.streamTubes());
}

void TestCapabilities::testContactCapabilities()
{
    ContactCapabilities contactCaps;
    // capabilities base
    QVERIFY(!contactCaps.isSpecificToContact());
    QVERIFY(!contactCaps.textChats());
    QVERIFY(!contactCaps.streamedMediaCalls());
    QVERIFY(!contactCaps.streamedMediaAudioCalls());
    QVERIFY(!contactCaps.streamedMediaVideoCalls());
    QVERIFY(!contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(!contactCaps.upgradingStreamedMediaCalls());
    QVERIFY(!contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar")));
    QVERIFY(contactCaps.streamTubeServices().isEmpty());

    RequestableChannelClassSpecList rccSpecs;
    rccSpecs.append(RequestableChannelClassSpec::textChat());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaAudioCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCall());
    rccSpecs.append(RequestableChannelClassSpec::streamedMediaVideoCallWithAudio());
    rccSpecs.append(RequestableChannelClassSpec::fileTransfer());

    contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true);
    // capabilities base
    QVERIFY(contactCaps.isSpecificToContact());
    QVERIFY(contactCaps.textChats());
    QVERIFY(contactCaps.streamedMediaCalls());
    QVERIFY(contactCaps.streamedMediaAudioCalls());
    QVERIFY(contactCaps.streamedMediaVideoCalls());
    QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(!contactCaps.streamTubes(QLatin1String("service-bar")));
    QVERIFY(contactCaps.streamTubeServices().isEmpty());
    QCOMPARE(contactCaps.allClassSpecs(), rccSpecs);

    rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-foo")));
    rccSpecs.append(RequestableChannelClassSpec::streamTube(QLatin1String("service-bar")));

    contactCaps = TestBackdoors::createContactCapabilities(rccSpecs, true);
    // capabilities base
    QVERIFY(contactCaps.isSpecificToContact());
    QVERIFY(contactCaps.textChats());
    QVERIFY(contactCaps.streamedMediaCalls());
    QVERIFY(contactCaps.streamedMediaAudioCalls());
    QVERIFY(contactCaps.streamedMediaVideoCalls());
    QVERIFY(contactCaps.streamedMediaVideoCallsWithAudio());
    QVERIFY(contactCaps.fileTransfers());
    // contact caps specific
    QVERIFY(!contactCaps.streamTubes(QLatin1String("foobar")));
    QVERIFY(contactCaps.streamTubes(QLatin1String("service-foo")));
    QVERIFY(contactCaps.streamTubes(QLatin1String("service-bar")));
    QStringList stubeServices = contactCaps.streamTubeServices();
    stubeServices.sort();
    QStringList expectedSTubeServices;
    expectedSTubeServices << QLatin1String("service-foo") << QLatin1String("service-bar");
    expectedSTubeServices.sort();
    QCOMPARE(stubeServices, expectedSTubeServices);
    QCOMPARE(contactCaps.allClassSpecs(), rccSpecs);
}

QTEST_MAIN(TestCapabilities)

#include "_gen/capabilities.cpp.moc.hpp"
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "JoinMenu.h"

/* system headers */
#include <string>
#include <vector>

/* common implementation headers */
#include "FontManager.h"

/* local implementation headers */
#include "StartupInfo.h"
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "MenuDefaultKey.h"
#include "ServerStartMenu.h"
#include "ServerMenu.h"
#include "Protocol.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "HUDuiTypeIn.h"
#include "HUDuiList.h"
#include "TimeKeeper.h"

/* from playing.h */
StartupInfo* getStartupInfo();
typedef void (*JoinGameCallback)(bool success, void* data);
void joinGame(JoinGameCallback, void* userData);
typedef void (*ConnectStatusCallback)(std::string& str);
void setConnectStatusCB(ConnectStatusCallback);
void drawFrame(const float dt);

JoinMenu* JoinMenu::activeMenu = NULL;

JoinMenu::JoinMenu() : oldErrorCallback(NULL),
		       serverStartMenu(NULL), serverMenu(NULL)
{
  // cache font face ID
  int fontFace = MainMenu::getFontFace();

  // add controls
  std::vector<HUDuiControl*>& list = getControls();
  StartupInfo* info = getStartupInfo();

  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(fontFace);
  label->setString("Join Game");
  list.push_back(label);

  findServer = new HUDuiLabel;
  findServer->setFontFace(fontFace);
  findServer->setString("Find Server");
  list.push_back(findServer);

  connectLabel = new HUDuiLabel;
  connectLabel->setFontFace(fontFace);
  connectLabel->setString("Connect");
  list.push_back(connectLabel);

  callsign = new HUDuiTypeIn;
  callsign->setFontFace(fontFace);
  callsign->setLabel("Callsign:");
  callsign->setMaxLength(CallSignLen - 1);
  callsign->setString(info->callsign);
  list.push_back(callsign);

  team = new HUDuiList;
  team->setFontFace(fontFace);
  team->setLabel("Team:");
  team->setCallback(teamCallback, NULL);
  std::vector<std::string>& teams = team->getList();
  // these do not need to be in enum order, but must match getTeam() & setTeam()
  teams.push_back(std::string(Team::getName(AutomaticTeam)));
  teams.push_back(std::string(Team::getName(RogueTeam)));
  teams.push_back(std::string(Team::getName(RedTeam)));
  teams.push_back(std::string(Team::getName(GreenTeam)));
  teams.push_back(std::string(Team::getName(BlueTeam)));
  teams.push_back(std::string(Team::getName(PurpleTeam)));
  teams.push_back(std::string(Team::getName(ObserverTeam)));
  team->update();
  setTeam(info->team);
  list.push_back(team);

  server = new HUDuiTypeIn;
  server->setFontFace(fontFace);
  server->setLabel("Server:");
  server->setMaxLength(64);
  server->setString(info->serverName);
  list.push_back(server);

  char buffer[10];
  sprintf(buffer, "%d", info->serverPort);
  port = new HUDuiTypeIn;
  port->setFontFace(fontFace);
  port->setLabel("Port:");
  port->setMaxLength(5);
  port->setString(buffer);
  list.push_back(port);

  email = new HUDuiTypeIn;
  email->setFontFace(fontFace);
  email->setLabel("Email:");
  email->setMaxLength(EmailLen - 1);
  email->setString(info->email);
  list.push_back(email);

  startServer = new HUDuiLabel;
  startServer->setFontFace(fontFace);
  startServer->setString("Start Server");
  list.push_back(startServer);

  status = new HUDuiLabel;
  status->setFontFace(fontFace);
  status->setString("");
  list.push_back(status);

  failedMessage = new HUDuiLabel;
  failedMessage->setFontFace(fontFace);
  failedMessage->setString("");
  list.push_back(failedMessage);

  initNavigation(list, 1, list.size() - 3);
}

JoinMenu::~JoinMenu()
{
  delete serverStartMenu;
  delete serverMenu;
}

HUDuiDefaultKey* JoinMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void JoinMenu::show()
{
  activeMenu = this;

  StartupInfo* info = getStartupInfo();

  // set fields
  callsign->setString(info->callsign);
  setTeam(info->team);

  server->setString(info->serverName);
  char buffer[10];
  sprintf(buffer, "%d", info->serverPort);
  port->setString(buffer);

  // clear status
  oldErrorCallback = NULL;
  setStatus("");
}

void JoinMenu::dismiss()
{
  loadInfo();
  setConnectStatusCB(NULL);
  activeMenu = NULL;
}

void JoinMenu::loadInfo()
{
  // load startup info with current settings
  StartupInfo* info = getStartupInfo();
  strcpy(info->callsign, callsign->getString().c_str());
  info->team = getTeam();
  strcpy(info->serverName, server->getString().c_str());
  info->serverPort = atoi(port->getString().c_str());
  strcpy(info->email, email->getString().c_str());
}

void JoinMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == startServer) {

    if (!serverStartMenu) serverStartMenu = new ServerStartMenu;
    HUDDialogStack::get()->push(serverStartMenu);

  } else if (focus == findServer) {

    if (!serverMenu) serverMenu = new ServerMenu;
    HUDDialogStack::get()->push(serverMenu);

  } else if (focus == connectLabel) {

    // load startup info
    loadInfo();

    // make sure we've got what we need
    StartupInfo* info = getStartupInfo();
    if (info->callsign[0] == '\0') {
      setStatus("You must enter a callsign.");
      return;
    }
    if (info->serverName[0] == '\0') {
      setStatus("You must enter a server.");
      return;
    }
    if (info->serverPort <= 0 || info->serverPort > 65535) {
      char buffer[60];
      sprintf(buffer, "Port is invalid.  Try %d.", ServerPort);
      setStatus(buffer);
      return;
    }

    // let user know we're trying
    setStatus("Trying...");

    // schedule attempt to join game
    oldErrorCallback = setErrorCallback(joinErrorCallback);
    setConnectStatusCB(&connectStatusCallback);
    joinGame(&joinGameCallback, this);
  }
}

void JoinMenu::joinGameCallback(bool okay, void* _self)
{
  JoinMenu* self = (JoinMenu*)_self;
  if (okay) {
    // it worked!  pop all the menus.
    HUDDialogStack* stack = HUDDialogStack::get();
    while (stack->isActive()) stack->pop();
  } else {
    // failed.  let user know.
    self->setStatus("Connection failed.");
  }
  setErrorCallback(self->oldErrorCallback);
  self->oldErrorCallback = NULL;
}

void JoinMenu::connectStatusCallback(std::string& str)
{
  static TimeKeeper prev = TimeKeeper::getNullTime();
  JoinMenu* self = activeMenu;

  self->setFailedMessage(str.c_str());

  // limit framerate to 2 fps - if you can't draw 2 fps you're screwed anyhow
  // if we draw too many fps then people with fast connections and slow computers
  // will have a problem on their hands, since we aren't multithreading

  const float dt = TimeKeeper::getCurrent() - prev;

  if (dt >= 0.5f) {
    // render that puppy
    drawFrame(dt);
    prev = TimeKeeper::getCurrent();
  }
}

void JoinMenu::joinErrorCallback(const char* msg)
{
  JoinMenu* self = activeMenu;

  self->setFailedMessage(msg);

  // also forward to old callback if it's not this callback
  if (self->oldErrorCallback && self->oldErrorCallback != self->joinErrorCallback) {
    (*self->oldErrorCallback)(msg);
  }
}

void JoinMenu::setFailedMessage(const char* msg)
{
  failedMessage->setString(msg);

  FontManager &fm = FontManager::instance();
  const float width = fm.getStrLength(MainMenu::getFontFace(),
	failedMessage->getFontSize(), failedMessage->getString());
  failedMessage->setPosition(center - 0.5f * width, failedMessage->getY());
}

TeamColor JoinMenu::getTeam() const
{
  return team->getIndex() == 0 ? AutomaticTeam : TeamColor(team->getIndex() - 1);
}

void JoinMenu::setTeam(TeamColor teamcol)
{
  team->setIndex(teamcol == AutomaticTeam ? 0 : int(teamcol) + 1);
}

void JoinMenu::setStatus(const char* msg, const std::vector<std::string> *)
{
  status->setString(msg);
  FontManager &fm = FontManager::instance();
  const float width = fm.getStrLength(status->getFontFace(),
		status->getFontSize(), status->getString());
  status->setPosition(center - 0.5f * width, status->getY());
  if (!oldErrorCallback) joinErrorCallback("");
}

void JoinMenu::teamCallback(HUDuiControl*, void*)
{
  // do nothing (for now)
}

void JoinMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)height / 15.0f;
  const float fontSize = (float)height / 36.0f;
  center = 0.5f * (float)width;

  FontManager &fm = FontManager::instance();

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(MainMenu::getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(MainMenu::getFontFace(), titleFontSize, "");
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleHeight;
  title->setPosition(x, y);

  // reposition options
  x = 0.5f * ((float)width - 0.5f * titleWidth);
  y -= 0.6f * titleHeight;
  list[1]->setFontSize(fontSize);
  const float h = fm.getStrHeight(MainMenu::getFontFace(), fontSize, "");
  const int count = list.size();
  for (int i = 1; i < count; i++) {
    list[i]->setFontSize(fontSize);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
    if (i <= 2 || i == 7) y -= 0.5f * h;
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>forming a pointer-to-member requires explicit use of the address-of operator ('&') and a qualified name<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "JoinMenu.h"

/* system headers */
#include <string>
#include <vector>

/* common implementation headers */
#include "FontManager.h"

/* local implementation headers */
#include "StartupInfo.h"
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "MenuDefaultKey.h"
#include "ServerStartMenu.h"
#include "ServerMenu.h"
#include "Protocol.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "HUDuiTypeIn.h"
#include "HUDuiList.h"
#include "TimeKeeper.h"

/* from playing.h */
StartupInfo* getStartupInfo();
typedef void (*JoinGameCallback)(bool success, void* data);
void joinGame(JoinGameCallback, void* userData);
typedef void (*ConnectStatusCallback)(std::string& str);
void setConnectStatusCB(ConnectStatusCallback);
void drawFrame(const float dt);

JoinMenu* JoinMenu::activeMenu = NULL;

JoinMenu::JoinMenu() : oldErrorCallback(NULL),
		       serverStartMenu(NULL), serverMenu(NULL)
{
  // cache font face ID
  int fontFace = MainMenu::getFontFace();

  // add controls
  std::vector<HUDuiControl*>& list = getControls();
  StartupInfo* info = getStartupInfo();

  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(fontFace);
  label->setString("Join Game");
  list.push_back(label);

  findServer = new HUDuiLabel;
  findServer->setFontFace(fontFace);
  findServer->setString("Find Server");
  list.push_back(findServer);

  connectLabel = new HUDuiLabel;
  connectLabel->setFontFace(fontFace);
  connectLabel->setString("Connect");
  list.push_back(connectLabel);

  callsign = new HUDuiTypeIn;
  callsign->setFontFace(fontFace);
  callsign->setLabel("Callsign:");
  callsign->setMaxLength(CallSignLen - 1);
  callsign->setString(info->callsign);
  list.push_back(callsign);

  team = new HUDuiList;
  team->setFontFace(fontFace);
  team->setLabel("Team:");
  team->setCallback(teamCallback, NULL);
  std::vector<std::string>& teams = team->getList();
  // these do not need to be in enum order, but must match getTeam() & setTeam()
  teams.push_back(std::string(Team::getName(AutomaticTeam)));
  teams.push_back(std::string(Team::getName(RogueTeam)));
  teams.push_back(std::string(Team::getName(RedTeam)));
  teams.push_back(std::string(Team::getName(GreenTeam)));
  teams.push_back(std::string(Team::getName(BlueTeam)));
  teams.push_back(std::string(Team::getName(PurpleTeam)));
  teams.push_back(std::string(Team::getName(ObserverTeam)));
  team->update();
  setTeam(info->team);
  list.push_back(team);

  server = new HUDuiTypeIn;
  server->setFontFace(fontFace);
  server->setLabel("Server:");
  server->setMaxLength(64);
  server->setString(info->serverName);
  list.push_back(server);

  char buffer[10];
  sprintf(buffer, "%d", info->serverPort);
  port = new HUDuiTypeIn;
  port->setFontFace(fontFace);
  port->setLabel("Port:");
  port->setMaxLength(5);
  port->setString(buffer);
  list.push_back(port);

  email = new HUDuiTypeIn;
  email->setFontFace(fontFace);
  email->setLabel("Email:");
  email->setMaxLength(EmailLen - 1);
  email->setString(info->email);
  list.push_back(email);

  startServer = new HUDuiLabel;
  startServer->setFontFace(fontFace);
  startServer->setString("Start Server");
  list.push_back(startServer);

  status = new HUDuiLabel;
  status->setFontFace(fontFace);
  status->setString("");
  list.push_back(status);

  failedMessage = new HUDuiLabel;
  failedMessage->setFontFace(fontFace);
  failedMessage->setString("");
  list.push_back(failedMessage);

  initNavigation(list, 1, list.size() - 3);
}

JoinMenu::~JoinMenu()
{
  delete serverStartMenu;
  delete serverMenu;
}

HUDuiDefaultKey* JoinMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void JoinMenu::show()
{
  activeMenu = this;

  StartupInfo* info = getStartupInfo();

  // set fields
  callsign->setString(info->callsign);
  setTeam(info->team);

  server->setString(info->serverName);
  char buffer[10];
  sprintf(buffer, "%d", info->serverPort);
  port->setString(buffer);

  // clear status
  oldErrorCallback = NULL;
  setStatus("");
}

void JoinMenu::dismiss()
{
  loadInfo();
  setConnectStatusCB(NULL);
  activeMenu = NULL;
}

void JoinMenu::loadInfo()
{
  // load startup info with current settings
  StartupInfo* info = getStartupInfo();
  strcpy(info->callsign, callsign->getString().c_str());
  info->team = getTeam();
  strcpy(info->serverName, server->getString().c_str());
  info->serverPort = atoi(port->getString().c_str());
  strcpy(info->email, email->getString().c_str());
}

void JoinMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == startServer) {

    if (!serverStartMenu) serverStartMenu = new ServerStartMenu;
    HUDDialogStack::get()->push(serverStartMenu);

  } else if (focus == findServer) {

    if (!serverMenu) serverMenu = new ServerMenu;
    HUDDialogStack::get()->push(serverMenu);

  } else if (focus == connectLabel) {

    // load startup info
    loadInfo();

    // make sure we've got what we need
    StartupInfo* info = getStartupInfo();
    if (info->callsign[0] == '\0') {
      setStatus("You must enter a callsign.");
      return;
    }
    if (info->serverName[0] == '\0') {
      setStatus("You must enter a server.");
      return;
    }
    if (info->serverPort <= 0 || info->serverPort > 65535) {
      char buffer[60];
      sprintf(buffer, "Port is invalid.  Try %d.", ServerPort);
      setStatus(buffer);
      return;
    }

    // let user know we're trying
    setStatus("Trying...");

    // schedule attempt to join game
    oldErrorCallback = setErrorCallback(joinErrorCallback);
    setConnectStatusCB(&connectStatusCallback);
    joinGame(&joinGameCallback, this);
  }
}

void JoinMenu::joinGameCallback(bool okay, void* _self)
{
  JoinMenu* self = (JoinMenu*)_self;
  if (okay) {
    // it worked!  pop all the menus.
    HUDDialogStack* stack = HUDDialogStack::get();
    while (stack->isActive()) stack->pop();
  } else {
    // failed.  let user know.
    self->setStatus("Connection failed.");
  }
  setErrorCallback(self->oldErrorCallback);
  self->oldErrorCallback = NULL;
}

void JoinMenu::connectStatusCallback(std::string& str)
{
  static TimeKeeper prev = TimeKeeper::getNullTime();
  JoinMenu* self = activeMenu;

  self->setFailedMessage(str.c_str());

  // limit framerate to 2 fps - if you can't draw 2 fps you're screwed anyhow
  // if we draw too many fps then people with fast connections and slow computers
  // will have a problem on their hands, since we aren't multithreading

  const float dt = TimeKeeper::getCurrent() - prev;

  if (dt >= 0.5f) {
    // render that puppy
    drawFrame(dt);
    prev = TimeKeeper::getCurrent();
  }
}

void JoinMenu::joinErrorCallback(const char* msg)
{
  JoinMenu* self = activeMenu;

  self->setFailedMessage(msg);

  // also forward to old callback if it's not this callback
  if (self->oldErrorCallback && self->oldErrorCallback != &JoinMenu::joinErrorCallback) {
    (*self->oldErrorCallback)(msg);
  }
}

void JoinMenu::setFailedMessage(const char* msg)
{
  failedMessage->setString(msg);

  FontManager &fm = FontManager::instance();
  const float width = fm.getStrLength(MainMenu::getFontFace(),
	failedMessage->getFontSize(), failedMessage->getString());
  failedMessage->setPosition(center - 0.5f * width, failedMessage->getY());
}

TeamColor JoinMenu::getTeam() const
{
  return team->getIndex() == 0 ? AutomaticTeam : TeamColor(team->getIndex() - 1);
}

void JoinMenu::setTeam(TeamColor teamcol)
{
  team->setIndex(teamcol == AutomaticTeam ? 0 : int(teamcol) + 1);
}

void JoinMenu::setStatus(const char* msg, const std::vector<std::string> *)
{
  status->setString(msg);
  FontManager &fm = FontManager::instance();
  const float width = fm.getStrLength(status->getFontFace(),
		status->getFontSize(), status->getString());
  status->setPosition(center - 0.5f * width, status->getY());
  if (!oldErrorCallback) joinErrorCallback("");
}

void JoinMenu::teamCallback(HUDuiControl*, void*)
{
  // do nothing (for now)
}

void JoinMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)height / 15.0f;
  const float fontSize = (float)height / 36.0f;
  center = 0.5f * (float)width;

  FontManager &fm = FontManager::instance();

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(MainMenu::getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(MainMenu::getFontFace(), titleFontSize, "");
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleHeight;
  title->setPosition(x, y);

  // reposition options
  x = 0.5f * ((float)width - 0.5f * titleWidth);
  y -= 0.6f * titleHeight;
  list[1]->setFontSize(fontSize);
  const float h = fm.getStrHeight(MainMenu::getFontFace(), fontSize, "");
  const int count = list.size();
  for (int i = 1; i < count; i++) {
    list[i]->setFontSize(fontSize);
    list[i]->setPosition(x, y);
    y -= 1.0f * h;
    if (i <= 2 || i == 7) y -= 0.5f * h;
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "MainMenu.h"

/* system implementationheaders */
#include <string>
#include <vector>

/* common implementation headers */
#include "TextureManager.h"
#include "FontManager.h"

/* local implementation headers */
#include "HelpMenu.h"
#include "HUDDialogStack.h"
#include "LocalPlayer.h"
#include "JoinMenu.h"
#ifdef HAVE_KRB5
#include "LoginMenu.h"
#endif
#include "OptionsMenu.h"
#include "QuitMenu.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "HUDuiTextureLabel.h"

/* from playing.cxx */
void leaveGame();

MainMenu::MainMenu() : HUDDialog(), joinMenu(NULL),
#ifdef HAVE_KRB5
		       loginMenu(NULL),
#endif
		       optionsMenu(NULL), quitMenu(NULL)
{
}

void	  MainMenu::createControls()
{
  TextureManager &tm = TextureManager::instance();
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiControl* label;
  HUDuiTextureLabel* textureLabel;

  // clear controls
  list.erase(list.begin(), list.end());

  // load title
  int title = tm.getTextureID("title");

  // add controls
  textureLabel = new HUDuiTextureLabel;
  textureLabel->setFontFace(getFontFace());
  textureLabel->setTexture(title);
  textureLabel->setString("BZFlag");
  list.push_back(textureLabel);

  label = createLabel("Up/Down arrows to move, Enter to select, Esc to dismiss");
  list.push_back(label);

  join = createLabel("Join Game");
  list.push_back(join);

#ifdef HAVE_KRB5
  login = createLabel("Login");
  list.push_back(login);
#endif

  options = createLabel("Options");
  list.push_back(options);

  help = createLabel("Help");
  list.push_back(help);

  LocalPlayer* myTank = LocalPlayer::getMyTank();
  if (!(myTank == NULL)) {
    leave = createLabel("Leave Game");
    list.push_back(leave);
  } else {
    leave = NULL;
  }

  quit = createLabel("Quit");
  list.push_back(quit);

  resize(HUDDialog::getWidth(), HUDDialog::getHeight());
  initNavigation(list, 2, list.size() - 1);

  // set focus back at the top in case the item we had selected does not exist anymore
  list[2]->setFocus();
}

HUDuiControl* MainMenu::createLabel(const char* string)
{
  HUDuiLabel* control = new HUDuiLabel;
  control->setFontFace(getFontFace());
  control->setString(string);
  return control;
}

MainMenu::~MainMenu()
{
  delete joinMenu;
#ifdef HAVE_KRB5
  delete loginMenu;
#endif
  delete optionsMenu;
  delete quitMenu;
  HelpMenu::done();
}

const int		MainMenu::getFontFace()
{
  // create font
  return FontManager::instance().getFaceID(BZDB.get("sansSerifFont"));
}

HUDuiDefaultKey*	MainMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void			MainMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == join) {
    if (!joinMenu) joinMenu = new JoinMenu;
    HUDDialogStack::get()->push(joinMenu);
#ifdef HAVE_KRB5
  } else if (focus == login) {
    if (!loginMenu) loginMenu = new LoginMenu;
    HUDDialogStack::get()->push(loginMenu);
#endif
  } else if (focus == options) {
    if (!optionsMenu) optionsMenu = new OptionsMenu;
    HUDDialogStack::get()->push(optionsMenu);
  } else if (focus == help) {
    HUDDialogStack::get()->push(HelpMenu::getHelpMenu());
  } else if (focus == leave) {
    leaveGame();
    // myTank should be NULL now, recreate menu
    createControls();
  } else if (focus == quit) {
    if (!quitMenu) quitMenu = new QuitMenu;
    HUDDialogStack::get()->push(quitMenu);
  }
}

void			MainMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // use a big font
  const float titleFontSize = (float)height / 8.0f;
  const float tinyFontSize = (float)height / 54.0f;
  const float fontSize = (float)height / 22.0f;
  FontManager &fm = FontManager::instance();
  int fontFace = getFontFace();

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  // scale appropriately to center properly
  TextureManager &tm = TextureManager::instance();
  float texHeight = (float)tm.getInfo(((HUDuiTextureLabel*)title)->getTexture()).y;
  float texWidth = (float)tm.getInfo(((HUDuiTextureLabel*)title)->getTexture()).x;
  float titleWidth = (texWidth / texHeight) * titleFontSize;
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFontSize * 1.25f;
  title->setPosition(x, y);

  // reposition instructions
  HUDuiLabel* hint = (HUDuiLabel*)list[1];
  hint->setFontSize(tinyFontSize);
  const float hintWidth = fm.getStrLength(fontFace, tinyFontSize, hint->getString());
  y -= 1.25f * fm.getStrHeight(fontFace, tinyFontSize, hint->getString());
  hint->setPosition(0.5f * ((float)width - hintWidth), y);
  y -= 1.5f * fm.getStrHeight(fontFace, fontSize, hint->getString());

  // reposition menu items (first is centered, rest aligned to the first)
  const float firstWidth = fm.getStrLength(fontFace, fontSize, ((HUDuiLabel*)list[2])->getString());
  x = 0.5f * ((float)width - firstWidth);
  const int count = list.size();
  for (int i = 2; i < count; i++) {
    HUDuiLabel* label = (HUDuiLabel*)list[i];
    label->setFontSize(fontSize);
    label->setPosition(x, y);
    y -= 1.2f * fm.getStrHeight(fontFace, fontSize, label->getString());
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>Don't leak memory here either<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "MainMenu.h"

/* system implementationheaders */
#include <string>
#include <vector>

/* common implementation headers */
#include "TextureManager.h"
#include "FontManager.h"

/* local implementation headers */
#include "HelpMenu.h"
#include "HUDDialogStack.h"
#include "LocalPlayer.h"
#include "JoinMenu.h"
#ifdef HAVE_KRB5
#include "LoginMenu.h"
#endif
#include "OptionsMenu.h"
#include "QuitMenu.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "HUDuiTextureLabel.h"

/* from playing.cxx */
void leaveGame();

MainMenu::MainMenu() : HUDDialog(), joinMenu(NULL),
#ifdef HAVE_KRB5
		       loginMenu(NULL),
#endif
		       optionsMenu(NULL), quitMenu(NULL)
{
}

void	  MainMenu::createControls()
{
  TextureManager &tm = TextureManager::instance();
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiControl* label;
  HUDuiTextureLabel* textureLabel;

  // clear controls
  for (unsigned int i = 0; i < list.size(); i++)
    delete list[i];
  list.erase(list.begin(), list.end());

  // load title
  int title = tm.getTextureID("title");

  // add controls
  textureLabel = new HUDuiTextureLabel;
  textureLabel->setFontFace(getFontFace());
  textureLabel->setTexture(title);
  textureLabel->setString("BZFlag");
  list.push_back(textureLabel);

  label = createLabel("Up/Down arrows to move, Enter to select, Esc to dismiss");
  list.push_back(label);

  join = createLabel("Join Game");
  list.push_back(join);

#ifdef HAVE_KRB5
  login = createLabel("Login");
  list.push_back(login);
#endif

  options = createLabel("Options");
  list.push_back(options);

  help = createLabel("Help");
  list.push_back(help);

  LocalPlayer* myTank = LocalPlayer::getMyTank();
  if (!(myTank == NULL)) {
    leave = createLabel("Leave Game");
    list.push_back(leave);
  } else {
    leave = NULL;
  }

  quit = createLabel("Quit");
  list.push_back(quit);

  resize(HUDDialog::getWidth(), HUDDialog::getHeight());
  initNavigation(list, 2, list.size() - 1);

  // set focus back at the top in case the item we had selected does not exist anymore
  list[2]->setFocus();
}

HUDuiControl* MainMenu::createLabel(const char* string)
{
  HUDuiLabel* control = new HUDuiLabel;
  control->setFontFace(getFontFace());
  control->setString(string);
  return control;
}

MainMenu::~MainMenu()
{
  // clear controls
  std::vector<HUDuiControl *>& list = getControls();
  for (unsigned int i = 0; i < list.size(); i++)
    delete list[i];
  list.erase(list.begin(), list.end());

  // destroy submenus
  delete joinMenu;
#ifdef HAVE_KRB5
  delete loginMenu;
#endif
  delete optionsMenu;
  delete quitMenu;
  HelpMenu::done();
}

const int		MainMenu::getFontFace()
{
  // create font
  return FontManager::instance().getFaceID(BZDB.get("sansSerifFont"));
}

HUDuiDefaultKey*	MainMenu::getDefaultKey()
{
  return MenuDefaultKey::getInstance();
}

void			MainMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == join) {
    if (!joinMenu) joinMenu = new JoinMenu;
    HUDDialogStack::get()->push(joinMenu);
#ifdef HAVE_KRB5
  } else if (focus == login) {
    if (!loginMenu) loginMenu = new LoginMenu;
    HUDDialogStack::get()->push(loginMenu);
#endif
  } else if (focus == options) {
    if (!optionsMenu) optionsMenu = new OptionsMenu;
    HUDDialogStack::get()->push(optionsMenu);
  } else if (focus == help) {
    HUDDialogStack::get()->push(HelpMenu::getHelpMenu());
  } else if (focus == leave) {
    leaveGame();
    // myTank should be NULL now, recreate menu
    createControls();
  } else if (focus == quit) {
    if (!quitMenu) quitMenu = new QuitMenu;
    HUDDialogStack::get()->push(quitMenu);
  }
}

void			MainMenu::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // use a big font
  const float titleFontSize = (float)height / 8.0f;
  const float tinyFontSize = (float)height / 54.0f;
  const float fontSize = (float)height / 22.0f;
  FontManager &fm = FontManager::instance();
  int fontFace = getFontFace();

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  // scale appropriately to center properly
  TextureManager &tm = TextureManager::instance();
  float texHeight = (float)tm.getInfo(((HUDuiTextureLabel*)title)->getTexture()).y;
  float texWidth = (float)tm.getInfo(((HUDuiTextureLabel*)title)->getTexture()).x;
  float titleWidth = (texWidth / texHeight) * titleFontSize;
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFontSize * 1.25f;
  title->setPosition(x, y);

  // reposition instructions
  HUDuiLabel* hint = (HUDuiLabel*)list[1];
  hint->setFontSize(tinyFontSize);
  const float hintWidth = fm.getStrLength(fontFace, tinyFontSize, hint->getString());
  y -= 1.25f * fm.getStrHeight(fontFace, tinyFontSize, hint->getString());
  hint->setPosition(0.5f * ((float)width - hintWidth), y);
  y -= 1.5f * fm.getStrHeight(fontFace, fontSize, hint->getString());

  // reposition menu items (first is centered, rest aligned to the first)
  const float firstWidth = fm.getStrLength(fontFace, fontSize, ((HUDuiLabel*)list[2])->getString());
  x = 0.5f * ((float)width - firstWidth);
  const int count = list.size();
  for (int i = 2; i < count; i++) {
    HUDuiLabel* label = (HUDuiLabel*)list[i];
    label->setFontSize(fontSize);
    label->setPosition(x, y);
    y -= 1.2f * fm.getStrHeight(fontFace, fontSize, label->getString());
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>/**
 * Derived from this blog post:
 * http://simmesimme.github.io/tutorials/2015/09/20/signal-slot
 */

#ifndef SIGNAL_HPP
#define SIGNAL_HPP

#include <functional>
#include <map>

// A signal object may call multiple slots with the
// same signature. You can connect functions to the signal
// which will be called when the emit() method on the
// signal object is invoked. Any argument passed to emit()
// will be passed to the given functions.

template <typename... Args> class Signal {

public:
  Signal() : current_id_(0) {}

  // copy creates new signal
  Signal(Signal const &other) : current_id_(0) {}

  // connects a member function to this Signal
  template <typename T> int ConnectMember(T *inst, void (T::*func)(Args...)) {
    return Connect([=](Args... args) { (inst->*func)(args...); });
  }

  // connects a const member function to this Signal
  template <typename T>
  int ConnectMember(T *inst, void (T::*func)(Args...) const) {
    return Connect([=](Args... args) { (inst->*func)(args...); });
  }

  // smart pointer support
  template <typename T>
  int ConnectMember(std::shared_ptr<T> inst, void (T::*func)(Args...)) {
    return Connect([=](Args... args) { std::mem_fn(func)(inst, args...); });
  }

  // smart pointer support
  template <typename T>
  int ConnectMember(std::shared_ptr<T> inst, void (T::*func)(Args...) const) {
    return Connect([=](Args... args) { std::mem_fn(func)(inst, args...); });
  }

  // connects a std::function to the signal. The returned
  // value can be used to disconnect the function again
  int Connect(std::function<void(Args...)> const &slot) const {
    slots_.insert(std::make_pair(++current_id_, slot));
    return current_id_;
  }

  // disconnects a previously connected function
  void Disconnect(int id) const { slots_.erase(id); }

  // disconnects all previously connected functions
  void DisconnectAll() const { slots_.clear(); }

  // calls all connected functions
  void Emit(Args... p) {
    for (auto it : slots_) {
      it.second(p...);
    }
  }

  // assignment creates new Signal
  Signal &operator=(Signal const &other) { DisconnectAll(); }

private:
  mutable std::map<int, std::function<void(Args...)>> slots_;
  mutable int current_id_;
};

#endif /* SIGNAL_HPP */<commit_msg>added include for tacc compilation errors<commit_after>/**
 * Derived from this blog post:
 * http://simmesimme.github.io/tutorials/2015/09/20/signal-slot
 */

#ifndef SIGNAL_HPP
#define SIGNAL_HPP

#include <functional>
#include <map>
#include <memory>

// A signal object may call multiple slots with the
// same signature. You can connect functions to the signal
// which will be called when the emit() method on the
// signal object is invoked. Any argument passed to emit()
// will be passed to the given functions.

template <typename... Args> class Signal {

public:
  Signal() : current_id_(0) {}

  // copy creates new signal
  Signal(Signal const &other) : current_id_(0) {}

  // connects a member function to this Signal
  template <typename T> int ConnectMember(T *inst, void (T::*func)(Args...)) {
    return Connect([=](Args... args) { (inst->*func)(args...); });
  }

  // connects a const member function to this Signal
  template <typename T>
  int ConnectMember(T *inst, void (T::*func)(Args...) const) {
    return Connect([=](Args... args) { (inst->*func)(args...); });
  }

  // smart pointer support
  template <typename T>
  int ConnectMember(std::shared_ptr<T> inst, void (T::*func)(Args...)) {
    return Connect([=](Args... args) { std::mem_fn(func)(inst, args...); });
  }

  // smart pointer support
  template <typename T>
  int ConnectMember(std::shared_ptr<T> inst, void (T::*func)(Args...) const) {
    return Connect([=](Args... args) { std::mem_fn(func)(inst, args...); });
  }

  // connects a std::function to the signal. The returned
  // value can be used to disconnect the function again
  int Connect(std::function<void(Args...)> const &slot) const {
    slots_.insert(std::make_pair(++current_id_, slot));
    return current_id_;
  }

  // disconnects a previously connected function
  void Disconnect(int id) const { slots_.erase(id); }

  // disconnects all previously connected functions
  void DisconnectAll() const { slots_.clear(); }

  // calls all connected functions
  void Emit(Args... p) {
    for (auto it : slots_) {
      it.second(p...);
    }
  }

  // assignment creates new Signal
  Signal &operator=(Signal const &other) { DisconnectAll(); }

private:
  mutable std::map<int, std::function<void(Args...)>> slots_;
  mutable int current_id_;
};

#endif /* SIGNAL_HPP */<|endoftext|>


<commit_before>#include <stdio.h>
#include <string>
#include <locale>
#include <codecvt>
#include <iostream>

// http://en.cppreference.com/w/cpp/language/string_literal
// http://en.cppreference.com/w/cpp/locale/codecvt_utf8
std::string ws2s(const std::wstring& wstr)
{
    using convert_wchar = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_wchar, wchar_t> converter;

    return converter.to_bytes(wstr);
}

std::wstring s2ws(const std::string& str)
{
    using convert_wchar = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_wchar, wchar_t> converter;

    return converter.from_bytes(str);
}

template<typename T>
std::string toUtf8(const T& str)
{
    using convert_type = std::codecvt_utf8<typename T::value_type>;
    std::wstring_convert<convert_type, typename T::value_type> converter;
    return converter.to_bytes(str);
}

int main()
{
    // http://stackoverflow.com/questions/17641718/how-to-output-unicode-characters-in-c-c
    std::ios::sync_with_stdio(false);     // for Linux gcc.
    std::locale::global(std::locale(""));
    std::wcout.imbue(std::locale(""));

    std::string str = "Hello World";
    std::string strZH = "這是中文";
    std::wstring wstr = L"這是中文";
    std::string strUtf8 = u8"這是中文";
    std::u16string strUtf16 = u"這是中文";
    std::u32string strUft32 = U"這是中文";

    std::cout  << "string: "  << str   << std::endl;
    std::cout  << "string: "  << strZH << std::endl;
    std::wcout << "wstring: " << wstr  << std::endl;

    std::cout  << "convert to string: "  << ws2s(wstr)  << std::endl;
    std::wcout << "convert to wstring: " << s2ws(strZH) << std::endl;

    std::cout  << "string-utf8: "  << strUtf8  << std::endl;
    std::cout  << "string-utf16 to utf8: " << toUtf8(strUtf16) << std::endl;
    std::cout  << "string-utf32 to utf8: " << toUtf8(strUft32) << std::endl;

    return 0;
}
<commit_msg>[cpp][std string] C++ raw string<commit_after>#include <stdio.h>
#include <string>
#include <locale>
#include <codecvt>
#include <iostream>

// http://en.cppreference.com/w/cpp/language/string_literal
// http://en.cppreference.com/w/cpp/locale/codecvt_utf8
std::string ws2s(const std::wstring& wstr)
{
    using convert_wchar = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_wchar, wchar_t> converter;

    return converter.to_bytes(wstr);
}

std::wstring s2ws(const std::string& str)
{
    using convert_wchar = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_wchar, wchar_t> converter;

    return converter.from_bytes(str);
}

template<typename T>
std::string toUtf8(const T& str)
{
    using convert_type = std::codecvt_utf8<typename T::value_type>;
    std::wstring_convert<convert_type, typename T::value_type> converter;
    return converter.to_bytes(str);
}

int main()
{
    // http://stackoverflow.com/questions/17641718/how-to-output-unicode-characters-in-c-c
    std::ios::sync_with_stdio(false);     // for Linux gcc.
    std::locale::global(std::locale(""));
    std::wcout.imbue(std::locale(""));

    std::string str = "Hello World";
    std::string strZH = "這是中文";
    std::string strRaw = R"(This is a "raw" string)";
    std::wstring wstr = L"這是中文";
    std::string strUtf8 = u8"這是中文";
    std::u16string strUtf16 = u"這是中文";
    std::u32string strUft32 = U"這是中文";

    std::cout  << "string: "  << str   << std::endl;
    std::cout  << "string: "  << strZH << std::endl;
    std::cout  << "raw string: "  << strRaw << std::endl;
    std::wcout << "wstring: " << wstr  << std::endl;

    std::cout  << "convert to string: "  << ws2s(wstr)  << std::endl;
    std::wcout << "convert to wstring: " << s2ws(strZH) << std::endl;

    std::cout  << "string-utf8: "  << strUtf8  << std::endl;
    std::cout  << "string-utf16 to utf8: " << toUtf8(strUtf16) << std::endl;
    std::cout  << "string-utf32 to utf8: " << toUtf8(strUft32) << std::endl;

    return 0;
}
<|endoftext|>