<commit_before>#include <boost/timer.hpp>

#include <iostream>
#include <fstream>

#include "search/BucketPriorityQueue.hpp"
#include "search/Constants.hpp"
#include "search/astar/AStar.hpp"
#include "search/hastar/HAStar.hpp"
#include "search/switchback/Switchback.hpp"
#include "tiles/Tiles.hpp"
#include "tiles/MacroTiles.hpp"

using namespace std;
using namespace boost;

typedef AStar<TilesInstance15, TilesNode15> TilesAStar;
typedef HAStar<TilesInstance15, TilesNode15> TilesHAStar;
typedef Switchback<TilesInstance15, TilesNode15> TilesSwitchback;

typedef AStar<MacroTilesInstance15, TilesNode15> MacroTilesAStar;
typedef HAStar<MacroTilesInstance15, TilesNode15> MacroTilesHAStar;
typedef Switchback<MacroTilesInstance15, TilesNode15> MacroTilesSwitchback;

void print_build_info(ostream &o)
{
  o << "tiles state hash caching is "
#ifdef CACHE_TILES_HASH_VALUE
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "tiles state blank index caching is "
#ifdef CACHE_TILES_BLANK_INDEX
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "node f-value caching is "
#ifdef CACHE_NODE_F_VALUE
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s H* caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_H_STAR
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s P-g caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_P_MINUS_G
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s optimal path caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_OPTIMAL_PATHS
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "NDEBUG is "
#ifdef NDEBUG
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "OUTPUT_SEARCH_PROGRESS is "
#ifdef OUTPUT_SEARCH_PROGRESS
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "INITIAL_CLOSED_SET_SIZE is " << INITIAL_CLOSED_SET_SIZE << endl;
}

void print_size_info(ostream &o)
{
  o << "sizeof(unsigned) is " << sizeof(unsigned) << endl
    << "sizeof(Tile) is " << sizeof(Tile) << endl
    << "sizeof(TileIndex) is " << sizeof(TileIndex) << endl
    << "sizeof(TileArray) is " << sizeof(TileArray) << endl
    << "sizeof(TileCost) is " << sizeof(TileCost) << endl
    << "sizeof(TilesState15) is " << sizeof(TilesState15) << endl
    << "sizeof(TilesNode15) is " << sizeof(TilesNode15) << endl
    << "sizeof(size_t) is " << sizeof(size_t) << endl
    << "sizeof(BucketPriorityQueue<TilesNode15>::ItemPointer) is "
    << sizeof(BucketPriorityQueue<TilesNode15>::ItemPointer) << endl;
}

void print_usage(ostream &o, const char *prog_name)
{
  o << "usage: " << prog_name << " DOMAIN ALGORITHM [FILE]" << endl
    << "where" << endl
    << "  DOMAIN is one of {tiles, macro_tiles}" << endl
    << "  ALGORITHM is one of {astar, hastar, switchback, hidastar}" << endl
    << "  FILE is the optional instance file to read from" << endl
    << endl
    << "If no file is specified, the instance is read from stdin." << endl;

  o << endl << endl;

  o << "Build Information:" << endl;
  print_build_info(o);
  o << endl;
  print_size_info(o);
  o << endl;
}

TilesInstance15 * get_tiles_instance(int argc, char *argv[])
{
  TilesInstance15 *instance;
  if (argc == 4) {
    ifstream infile(argv[3]);
    instance = readTilesInstance15(infile);
  }
  else {
    instance = readTilesInstance15(cin);
  }

  if (instance == NULL) {
    cerr << "error reading instance!" << endl;
    exit(1);
  }

  return instance;
}

MacroTilesInstance15 * get_macro_tiles_instance(int argc, char *argv[])
{
  return new MacroTilesInstance15(get_tiles_instance(argc, argv));
}

template <class Searcher>
void search(Searcher &searcher)
{
  cout << "######## Search Results ########" << endl;

  timer search_timer;
  searcher.search();

  const TilesNode15 *goal = searcher.get_goal();
  if (goal == NULL) {
    cout << "no solution found!" << endl;
  }
  else {
    cout << "found a solution:" << endl;
    cout << *goal << endl;
    assert(goal->num_nodes_to_start() == goal->get_g() + 1u);
  }

  const double seconds_elapsed = search_timer.elapsed();
  const unsigned exp_per_second = searcher.get_num_expanded() / seconds_elapsed;
  const unsigned gen_per_second = searcher.get_num_expanded() / seconds_elapsed;

  cout << searcher.get_num_expanded() << " expanded ("
       << exp_per_second << "/s)" << endl
       << searcher.get_num_generated() << " generated ("
       << gen_per_second << "/s)" << endl
       << search_timer.elapsed() << "s" << endl;
}

int main(int argc, char * argv[])
{
  if (argc < 3 || argc > 4) {
    print_usage(cerr, argv[0]);
    return 1;
  }

  const string domain_string(argv[1]);
  const string alg_string(argv[2]);

  const bool is_tiles = domain_string == "tiles";
  const bool is_macro_tiles = domain_string == "macro_tiles";

  const bool is_astar = alg_string == "astar";
  const bool is_hastar = alg_string == "hastar";
  const bool is_hidastar = alg_string == "hidastar";
  const bool is_switchback = alg_string == "switchback";

  if (is_tiles && is_astar) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    TilesAStar &astar = *new TilesAStar(*instance);
    search(astar);
  }
  else if (is_tiles && is_hastar) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    TilesHAStar &hastar = *new TilesHAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(hastar);
  }
  else if (is_tiles && is_hidastar) {
    cerr << "HIDA* unimplemented" << endl;
    exit(1);
  }
  else if (is_tiles && is_switchback) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    TilesSwitchback &switchback = *new TilesSwitchback(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(switchback);
  }
  else if (is_macro_tiles && is_astar) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesAStar &astar = *new MacroTilesAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(astar);
  }
  else if (is_macro_tiles && is_hastar) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesHAStar &hastar = *new MacroTilesHAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(hastar);
  }
  else if (is_macro_tiles && is_hidastar) {
    cerr << "HIDA* unimplemented" << endl;
  }
  else if (is_macro_tiles && is_switchback) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesSwitchback &switchback = *new MacroTilesSwitchback(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(switchback);
  }
  else if (!is_tiles && !is_macro_tiles) {
    cerr << "error: invalid domain specified" << endl;
    print_usage(cerr, argv[0]);
    return 1;
  }
  else if (!is_astar && !is_hastar && !is_hidastar && !is_switchback) {
    cerr << "error: invalid algorithm specified" << endl;
    print_usage(cerr, argv[0]);
    return 1;
  }

  return 0;
}
<commit_msg>Bugfix in generation rate reporting.<commit_after>#include <boost/timer.hpp>

#include <iostream>
#include <fstream>

#include "search/BucketPriorityQueue.hpp"
#include "search/Constants.hpp"
#include "search/astar/AStar.hpp"
#include "search/hastar/HAStar.hpp"
#include "search/switchback/Switchback.hpp"
#include "tiles/Tiles.hpp"
#include "tiles/MacroTiles.hpp"

using namespace std;
using namespace boost;

typedef AStar<TilesInstance15, TilesNode15> TilesAStar;
typedef HAStar<TilesInstance15, TilesNode15> TilesHAStar;
typedef Switchback<TilesInstance15, TilesNode15> TilesSwitchback;

typedef AStar<MacroTilesInstance15, TilesNode15> MacroTilesAStar;
typedef HAStar<MacroTilesInstance15, TilesNode15> MacroTilesHAStar;
typedef Switchback<MacroTilesInstance15, TilesNode15> MacroTilesSwitchback;

void print_build_info(ostream &o)
{
  o << "tiles state hash caching is "
#ifdef CACHE_TILES_HASH_VALUE
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "tiles state blank index caching is "
#ifdef CACHE_TILES_BLANK_INDEX
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "node f-value caching is "
#ifdef CACHE_NODE_F_VALUE
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s H* caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_H_STAR
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s P-g caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_P_MINUS_G
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "Hierarchical A*'s optimal path caching is "
#ifdef HIERARCHICAL_A_STAR_CACHE_OPTIMAL_PATHS
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "NDEBUG is "
#ifdef NDEBUG
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "OUTPUT_SEARCH_PROGRESS is "
#ifdef OUTPUT_SEARCH_PROGRESS
    << "enabled" << endl;
#else
    << "disabled" << endl;
#endif

  o << "INITIAL_CLOSED_SET_SIZE is " << INITIAL_CLOSED_SET_SIZE << endl;
}

void print_size_info(ostream &o)
{
  o << "sizeof(unsigned) is " << sizeof(unsigned) << endl
    << "sizeof(Tile) is " << sizeof(Tile) << endl
    << "sizeof(TileIndex) is " << sizeof(TileIndex) << endl
    << "sizeof(TileArray) is " << sizeof(TileArray) << endl
    << "sizeof(TileCost) is " << sizeof(TileCost) << endl
    << "sizeof(TilesState15) is " << sizeof(TilesState15) << endl
    << "sizeof(TilesNode15) is " << sizeof(TilesNode15) << endl
    << "sizeof(size_t) is " << sizeof(size_t) << endl
    << "sizeof(BucketPriorityQueue<TilesNode15>::ItemPointer) is "
    << sizeof(BucketPriorityQueue<TilesNode15>::ItemPointer) << endl;
}

void print_usage(ostream &o, const char *prog_name)
{
  o << "usage: " << prog_name << " DOMAIN ALGORITHM [FILE]" << endl
    << "where" << endl
    << "  DOMAIN is one of {tiles, macro_tiles}" << endl
    << "  ALGORITHM is one of {astar, hastar, switchback, hidastar}" << endl
    << "  FILE is the optional instance file to read from" << endl
    << endl
    << "If no file is specified, the instance is read from stdin." << endl;

  o << endl << endl;

  o << "Build Information:" << endl;
  print_build_info(o);
  o << endl;
  print_size_info(o);
  o << endl;
}

TilesInstance15 * get_tiles_instance(int argc, char *argv[])
{
  TilesInstance15 *instance;
  if (argc == 4) {
    ifstream infile(argv[3]);
    instance = readTilesInstance15(infile);
  }
  else {
    instance = readTilesInstance15(cin);
  }

  if (instance == NULL) {
    cerr << "error reading instance!" << endl;
    exit(1);
  }

  return instance;
}

MacroTilesInstance15 * get_macro_tiles_instance(int argc, char *argv[])
{
  return new MacroTilesInstance15(get_tiles_instance(argc, argv));
}

template <class Searcher>
void search(Searcher &searcher)
{
  cout << "######## Search Results ########" << endl;

  timer search_timer;
  searcher.search();

  const TilesNode15 *goal = searcher.get_goal();
  if (goal == NULL) {
    cout << "no solution found!" << endl;
  }
  else {
    cout << "found a solution:" << endl;
    cout << *goal << endl;
    assert(goal->num_nodes_to_start() == goal->get_g() + 1u);
  }

  const double seconds_elapsed = search_timer.elapsed();
  const unsigned exp_per_second = searcher.get_num_expanded() / seconds_elapsed;
  const unsigned gen_per_second = searcher.get_num_generated() / seconds_elapsed;

  cout << searcher.get_num_expanded() << " expanded ("
       << exp_per_second << "/s)" << endl
       << searcher.get_num_generated() << " generated ("
       << gen_per_second << "/s)" << endl
       << search_timer.elapsed() << "s" << endl;
}

int main(int argc, char * argv[])
{
  if (argc < 3 || argc > 4) {
    print_usage(cerr, argv[0]);
    return 1;
  }

  const string domain_string(argv[1]);
  const string alg_string(argv[2]);

  const bool is_tiles = domain_string == "tiles";
  const bool is_macro_tiles = domain_string == "macro_tiles";

  const bool is_astar = alg_string == "astar";
  const bool is_hastar = alg_string == "hastar";
  const bool is_hidastar = alg_string == "hidastar";
  const bool is_switchback = alg_string == "switchback";

  if (is_tiles && is_astar) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    TilesAStar &astar = *new TilesAStar(*instance);
    search(astar);
  }
  else if (is_tiles && is_hastar) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    TilesHAStar &hastar = *new TilesHAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(hastar);
  }
  else if (is_tiles && is_hidastar) {
    cerr << "HIDA* unimplemented" << endl;
    exit(1);
  }
  else if (is_tiles && is_switchback) {
    TilesInstance15 *instance = get_tiles_instance(argc, argv);
    TilesSwitchback &switchback = *new TilesSwitchback(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(switchback);
  }
  else if (is_macro_tiles && is_astar) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesAStar &astar = *new MacroTilesAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(astar);
  }
  else if (is_macro_tiles && is_hastar) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesHAStar &hastar = *new MacroTilesHAStar(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(hastar);
  }
  else if (is_macro_tiles && is_hidastar) {
    cerr << "HIDA* unimplemented" << endl;
  }
  else if (is_macro_tiles && is_switchback) {
    MacroTilesInstance15 *instance = get_macro_tiles_instance(argc, argv);
    MacroTilesSwitchback &switchback = *new MacroTilesSwitchback(*instance);
    cout << "######## The Instance ########" << endl;
    cout << *instance << endl << endl;
    search(switchback);
  }
  else if (!is_tiles && !is_macro_tiles) {
    cerr << "error: invalid domain specified" << endl;
    print_usage(cerr, argv[0]);
    return 1;
  }
  else if (!is_astar && !is_hastar && !is_hidastar && !is_switchback) {
    cerr << "error: invalid algorithm specified" << endl;
    print_usage(cerr, argv[0]);
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>///
/// @file  Status.cpp
/// @brief The Status class is used to print the status (in percent)
///        of the formulas related to special leaves. It is used by
///        the D, S2_easy and S2_hard formulas.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <Status.hpp>
#include <primecount-internal.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <print.hpp>

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>

#if defined(_OPENMP)
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Since the distribution of the special leaves is highly skewed
/// we cannot simply calculate the percentage of the current
/// computation using the standard linear formula. Hence we use
/// a polynomial formula that grows faster when the value is
/// small and slower towards the end (100%).
/// Curve fitting tool: https://planetcalc.com/8735/
///
template <typename T>
double skewed_percent(T x, T y)
{
  double p1 = get_percent(x, y);
  double p2 = p1 * p1;
  double p3 = p1 * p2;
  double p4 = p2 * p2;

  double c1 = 3.70559815037356886459;
  double c2 = 0.07330455122609925077;
  double c3 = 0.00067895345810494585;
  double c4 = 0.00000216467760881310;

  double percent = -c4*p4 + c3*p3 - c2*p2 + c1*p1;
  percent = in_between(0, percent, 100);
  return percent;
}

} // namespace

namespace primecount {

Status::Status(maxint_t x)
{
  precision_ = get_status_precision(x);
  int q = ipow(10, precision_);
  epsilon_ = 1.0 / q;
}

bool Status::isPrint(double time)
{
  double old = time_;
  return old == 0 ||
        (time - old) >= is_print_;
}

void Status::print(double percent)
{
  double old = percent_;

  if ((percent - old) >= epsilon_)
  {
    percent_ = percent;
    ostringstream status;
    status << "\rStatus: " << fixed << setprecision(precision_) << percent << "%";
    cout << status.str() << flush;
  }
}

/// This method is used by S2_hard() and D().
/// This method does not use a lock to synchronize threads
/// as it is only used inside of a critical section inside
/// LoadBalancer.cpp and hence it can never be accessed
/// simultaneously from multiple threads.
///
double Status::getPercent(int64_t low, int64_t limit, maxint_t sum, maxint_t sum_approx)
{
  double p1 = skewed_percent(low, limit);
  double p2 = skewed_percent(sum, sum_approx);

  // When p1 is larger then p2 it is
  // always much more accurate.
  if (p1 > p2)
    return p1;

  // p2 is a very rough estimation, hence
  // we want to decrease its contribution
  // to the final percent value.
  double percent = (p1 * 6 + p2 * 4) / 10;

  return percent;
}

/// This method is used by S2_hard() and D().
/// This method does not use a lock to synchronize threads
/// as it is only used inside of a critical section inside
/// LoadBalancer.cpp and hence it can never be accessed
/// simultaneously from multiple threads.
///
void Status::print(int64_t low, int64_t limit, maxint_t sum, maxint_t sum_approx)
{
  // check --status option used
  if (!is_print())
    return;

  double time = get_time();

  if (isPrint(time))
  {
    time_ = time;
    double percent = getPercent(low, limit, sum, sum_approx);
    print(percent);
  }
}

/// Used by S2_easy
void Status::print(int64_t b, int64_t max_b)
{
  // check --status option used
  if (!is_print())
    return;

#if defined(_OPENMP)
  // In order to prevent data races only one thread at a time
  // can enter this code section. In order to make sure that
  // our code scales well up to a very large number of CPU
  // cores, we don't want to use any thread synchronization!
  // In order to achieve this only one of the threads (the
  // main thread) is allowed to print the status, while all
  // other threads do nothing.
  if (omp_get_thread_num() != 0)
    return;
#endif

  double time = get_time();

  if (isPrint(time))
  {
    time_ = time;
    double percent = skewed_percent(b, max_b);
    print(percent);
  }
}

} // namespace
<commit_msg>Improve status accuracy<commit_after>///
/// @file  Status.cpp
/// @brief The Status class is used to print the status (in percent)
///        of the formulas related to special leaves. It is used by
///        the D, S2_easy and S2_hard formulas.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <Status.hpp>
#include <primecount-internal.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <print.hpp>

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>

#if defined(_OPENMP)
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Since the distribution of the special leaves is highly skewed
/// we cannot simply calculate the percentage of the current
/// computation using the standard linear formula. Hence we use
/// a polynomial formula that grows faster when the value is
/// small and slower towards the end (100%).
/// Curve fitting tool: https://planetcalc.com/8735/
///
template <typename T>
double skewed_percent(T x, T y)
{
  double p1 = get_percent(x, y);
  double p2 = p1 * p1;
  double p3 = p1 * p2;
  double p4 = p2 * p2;

  double c1 = 3.70559815037356886459;
  double c2 = 0.07330455122609925077;
  double c3 = 0.00067895345810494585;
  double c4 = 0.00000216467760881310;

  double percent = -c4*p4 + c3*p3 - c2*p2 + c1*p1;
  percent = in_between(0, percent, 100);
  return percent;
}

} // namespace

namespace primecount {

Status::Status(maxint_t x)
{
  precision_ = get_status_precision(x);
  int q = ipow(10, precision_);
  epsilon_ = 1.0 / q;
}

bool Status::isPrint(double time)
{
  double old = time_;
  return old == 0 ||
        (time - old) >= is_print_;
}

void Status::print(double percent)
{
  double old = percent_;

  if ((percent - old) >= epsilon_)
  {
    percent_ = percent;
    ostringstream status;
    status << "\rStatus: " << fixed << setprecision(precision_) << percent << "%";
    cout << status.str() << flush;
  }
}

/// This method is used by S2_hard() and D().
/// This method does not use a lock to synchronize threads
/// as it is only used inside of a critical section inside
/// LoadBalancer.cpp and hence it can never be accessed
/// simultaneously from multiple threads.
///
double Status::getPercent(int64_t low, int64_t limit, maxint_t sum, maxint_t sum_approx)
{
  double p1 = skewed_percent(sum, sum_approx);
  double p2 = skewed_percent(low, limit);

  // When p2 is larger then p1 it is
  // always much more accurate.
  if (p2 > p1)
    return p2;

  // Below 20% p1 is better
  // Above 70% p2 is better
  double c1 = 150 / max(p1, 1.0);
  c1 = in_between(10, c1, 4);
  double c2 = 10 - c1;
  double percent = (c1*p1 + c2*p2) / 10;

  return percent;
}

/// This method is used by S2_hard() and D().
/// This method does not use a lock to synchronize threads
/// as it is only used inside of a critical section inside
/// LoadBalancer.cpp and hence it can never be accessed
/// simultaneously from multiple threads.
///
void Status::print(int64_t low, int64_t limit, maxint_t sum, maxint_t sum_approx)
{
  // check --status option used
  if (!is_print())
    return;

  double time = get_time();

  if (isPrint(time))
  {
    time_ = time;
    double percent = getPercent(low, limit, sum, sum_approx);
    print(percent);
  }
}

/// Used by S2_easy
void Status::print(int64_t b, int64_t max_b)
{
  // check --status option used
  if (!is_print())
    return;

#if defined(_OPENMP)
  // In order to prevent data races only one thread at a time
  // can enter this code section. In order to make sure that
  // our code scales well up to a very large number of CPU
  // cores, we don't want to use any thread synchronization!
  // In order to achieve this only one of the threads (the
  // main thread) is allowed to print the status, while all
  // other threads do nothing.
  if (omp_get_thread_num() != 0)
    return;
#endif

  double time = get_time();

  if (isPrint(time))
  {
    time_ = time;
    double percent = skewed_percent(b, max_b);
    print(percent);
  }
}

} // namespace
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 <cassert>
#include <cstdlib>
#include "ast.hh"

namespace {
/**
 * The current AST container.  When constructing an object, this is set and
 * then the constructors for the fields run, accessing it to detect their
 * parents.
 */
// FIXME: Should be thread_local, but that doesn't seem to work on OS X for
// some reason (__thread does)
__thread pegmatite::ASTContainer *current = 0;
/**
 * The current parser delegate.  When constructing an object, this is set and
 * then the constructors for the fields run, accessing it to detect their
 * parents.
 */
__thread pegmatite::ASTParserDelegate *currentParserDelegate;
}

namespace pegmatite {

std::string demangle(std::string mangled)
{
	int err;
	size_t s;
	char *buffer = static_cast<char*>(malloc(mangled.length()));

	char *demangled = abi::__cxa_demangle(mangled.c_str(), buffer, &s, &err);
	std::string result = demangled ? demangled : mangled;

	free(demangled ? demangled : buffer);

	return result;
}

/**
 * Out-of-line virtual destructor forces vtable to be emitted in this
 * translation unit only.
 */
ASTNode::~ASTNode()
{
}

/** sets the container under construction to be this.
 */
ASTContainer::ASTContainer()
{
	current = this;
}

/** Asks all members to construct themselves from the stack.
	The members are asked to construct themselves in reverse order.
	from a node stack.
	@param st stack.
 */
void ASTContainer::construct(const InputRange &r, ASTStack &st)
{
	for(auto it = members.rbegin(); it != members.rend(); ++it)
	{
		ASTMember *member = *it;
		member->construct(r, st);
	}
	// We don't need the members vector anymore, so clean up the storage it
	// uses.
	ASTMember_vector().swap(members);
}

ASTMember::ASTMember()
{
	assert(current && "ASTMember must be contained within an ASTContainer");
	container_node = current;
	current->members.push_back(this);
}
ASTMember::~ASTMember() {}

ASTParserDelegate::ASTParserDelegate()
{
	currentParserDelegate = this;
}

void ASTParserDelegate::set_parse_proc(const Rule &r, parse_proc p)
{
	handlers[std::addressof(r)] = p;
}
void ASTParserDelegate::bind_parse_proc(const Rule &r, parse_proc p)
{
	currentParserDelegate->set_parse_proc(r, p);
}
parse_proc ASTParserDelegate::get_parse_proc(const Rule &r) const
{
	auto it = handlers.find(std::addressof(r));
	if (it == handlers.end()) return 0;
	return it->second;
}

/** parses the given input.
	@param input input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param err callback for reporting errors.
	@param d user data, passed to the parse procedures.
	@return pointer to AST node created, or null if there was an Error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &input, const Rule &g, const Rule &ws,
                               ErrorReporter err, const ParserDelegate &d)
{
	ASTStack st;
	if (!parse(input, g, ws, err, d, &st)) return 0;
	if (st.size() > 1)
	{
		int i = 0;
		for (auto &I : st)
		{
			auto *val = I.second.get();
			fprintf(stderr, "[%d] %s\n", i++, typeid(*val).name());
		}
	}
	assert(st.size() == 1);
	return std::move(st[0].second);
}

} //namespace pegmatite
<commit_msg>Don't pass uninitialized size to __cxa_demangle().<commit_after>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 <cassert>
#include <cstdlib>
#include "ast.hh"

namespace {
/**
 * The current AST container.  When constructing an object, this is set and
 * then the constructors for the fields run, accessing it to detect their
 * parents.
 */
// FIXME: Should be thread_local, but that doesn't seem to work on OS X for
// some reason (__thread does)
__thread pegmatite::ASTContainer *current = 0;
/**
 * The current parser delegate.  When constructing an object, this is set and
 * then the constructors for the fields run, accessing it to detect their
 * parents.
 */
__thread pegmatite::ASTParserDelegate *currentParserDelegate;
}

namespace pegmatite {

std::string demangle(std::string mangled)
{
	int err;
	size_t s = 0;
	char *buffer = static_cast<char*>(malloc(mangled.length() + 1));

	char *demangled = abi::__cxa_demangle(mangled.c_str(), buffer, &s, &err);
	std::string result = demangled ? demangled : mangled;

	free(demangled ? demangled : buffer);

	return result;
}

/**
 * Out-of-line virtual destructor forces vtable to be emitted in this
 * translation unit only.
 */
ASTNode::~ASTNode()
{
}

/** sets the container under construction to be this.
 */
ASTContainer::ASTContainer()
{
	current = this;
}

/** Asks all members to construct themselves from the stack.
	The members are asked to construct themselves in reverse order.
	from a node stack.
	@param st stack.
 */
void ASTContainer::construct(const InputRange &r, ASTStack &st)
{
	for(auto it = members.rbegin(); it != members.rend(); ++it)
	{
		ASTMember *member = *it;
		member->construct(r, st);
	}
	// We don't need the members vector anymore, so clean up the storage it
	// uses.
	ASTMember_vector().swap(members);
}

ASTMember::ASTMember()
{
	assert(current && "ASTMember must be contained within an ASTContainer");
	container_node = current;
	current->members.push_back(this);
}
ASTMember::~ASTMember() {}

ASTParserDelegate::ASTParserDelegate()
{
	currentParserDelegate = this;
}

void ASTParserDelegate::set_parse_proc(const Rule &r, parse_proc p)
{
	handlers[std::addressof(r)] = p;
}
void ASTParserDelegate::bind_parse_proc(const Rule &r, parse_proc p)
{
	currentParserDelegate->set_parse_proc(r, p);
}
parse_proc ASTParserDelegate::get_parse_proc(const Rule &r) const
{
	auto it = handlers.find(std::addressof(r));
	if (it == handlers.end()) return 0;
	return it->second;
}

/** parses the given input.
	@param input input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param err callback for reporting errors.
	@param d user data, passed to the parse procedures.
	@return pointer to AST node created, or null if there was an Error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &input, const Rule &g, const Rule &ws,
                               ErrorReporter err, const ParserDelegate &d)
{
	ASTStack st;
	if (!parse(input, g, ws, err, d, &st)) return 0;
	if (st.size() > 1)
	{
		int i = 0;
		for (auto &I : st)
		{
			auto *val = I.second.get();
			fprintf(stderr, "[%d] %s\n", i++, typeid(*val).name());
		}
	}
	assert(st.size() == 1);
	return std::move(st[0].second);
}

} //namespace pegmatite
<|endoftext|>


<commit_before>/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003 T. Zachary Laine

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

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

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.

   Zach Laine
   whatwasthataddress@hotmail.com */

/* $Id: Edit.cpp 528 2006-03-04 02:56:33Z tzlaine $ */

#include <GG/TabWnd.h>

#ifndef _GG_DrawUtil_h_
#include <GG/DrawUtil.h>
#endif

#ifndef _GG_Layout_h_
#include <GG/Layout.h>
#endif

#ifndef _GG_StyleFactory_h_
#include <GG/StyleFactory.h>
#endif

using namespace GG;

namespace {
    int TabHeightFromFont(const boost::shared_ptr<Font>& font)
    { return font->Lineskip() + 10; }
}

////////////////////////////////////////////////
// GG::TabWnd
////////////////////////////////////////////////
// static(s)
const int TabWnd::NO_WND = RadioButtonGroup::NO_BUTTON;

TabWnd::TabWnd() :
    m_tab_bar(0),
    m_current_wnd(0)
{}

TabWnd::~TabWnd()
{
    for (unsigned int i = 0; i < m_wnds.size(); ++i) {
        delete m_wnds[i].first;
    }
}

TabWnd::TabWnd(int x, int y, int w, int h, const boost::shared_ptr<Font>& font, Clr color, Clr text_color/* = CLR_BLACK*/,
               TabBarStyle style/* = TAB_BAR_ATTACHED*/, Uint32 flags/* = CLICKABLE | DRAGABLE*/) :
    Wnd(x, y, w, h, flags),
    m_tab_bar(GetStyleFactory()->NewTabBar(0, 0, w, font, color, text_color, style, CLICKABLE)),
    m_current_wnd(0)
{
    Layout* layout = new Layout(0, 0, w, h, 2, 1);
    layout->SetRowStretch(1, 1.0);
    layout->Add(m_tab_bar, 0, 0);
    SetLayout(layout);
    Connect(m_tab_bar->TabChangedSignal, &TabWnd::TabChanged, this);
}

Pt TabWnd::MinUsableSize() const
{
    Pt retval = m_tab_bar->MinUsableSize();
    retval.y *= 2;
    return retval;
}

int TabWnd::CurrentWnd() const
{ return m_tab_bar->CurrentTab(); }

void TabWnd::Render()
{}

void TabWnd::AddWnd(Wnd* wnd, const std::string& name)
{ InsertWnd(m_wnds.size(), wnd, name); }

void TabWnd::InsertWnd(int index, Wnd* wnd, const std::string& name)
{
    m_wnds.insert(m_wnds.begin() + index, std::make_pair(wnd, name));
    m_tab_bar->InsertTab(index, name);
    GetLayout()->SetMinimumRowHeight(0, m_tab_bar->MinUsableSize().y + 2 * 5);
}

Wnd* TabWnd::RemoveWnd(const std::string& name)
{
    Wnd* retval = 0;
    int index = NO_WND;
    for (unsigned int i = 0; i < m_wnds.size(); ++i) {
        if (m_wnds[i].second == name) {
            index = i;
            break;
        }
    }
    if (index != NO_WND) {
        retval = m_wnds[index].first;
        m_wnds.erase(m_wnds.begin() + index);
        m_tab_bar->RemoveTab(name);
        GetLayout()->SetMinimumRowHeight(0, m_tab_bar->MinUsableSize().y + 2 * 5);
    }
    return retval;
}

void TabWnd::SetCurrentWnd(int index)
{ m_tab_bar->SetCurrentTab(index); }

const TabBar* TabWnd::GetTabBar() const
{ return m_tab_bar; }

const std::vector<std::pair<Wnd*, std::string> >& TabWnd::Wnds() const
{ return m_wnds; }

void TabWnd::TabChanged(int index)
{
    assert(0 <= index && index < static_cast<int>(m_wnds.size()));
    Wnd* old_current_wnd = m_current_wnd;
    m_current_wnd = m_wnds[index].first;
    if (m_current_wnd != old_current_wnd) {
        Layout* layout = GetLayout();
        layout->Remove(old_current_wnd);
        layout->Add(m_current_wnd, 1, 0);
    }
    WndChangedSignal(index);
}

////////////////////////////////////////////////
// GG::TabBar
////////////////////////////////////////////////
// static(s)
const int TabBar::NO_TAB = TabWnd::NO_WND;
const int TabBar::BUTTON_WIDTH = 10;

TabBar::TabBar() :
    Control(),
    m_tabs(0),
    m_left_button(0),
    m_right_button(0),
    m_left_right_button_layout(0),
    m_text_color(CLR_BLACK),
    m_style(TAB_BAR_ATTACHED),
    m_first_tab_shown(0)
{}

TabBar::TabBar(int x, int y, int w, const boost::shared_ptr<Font>& font, Clr color, Clr text_color/* = CLR_BLACK*/,
               TabBarStyle style/* = TAB_BAR_ATTACHED*/, Uint32 flags/* = CLICKABLE*/) :
    Control(x, y, w, TabHeightFromFont(font), flags),
    m_tabs(0),
    m_font(font),
    m_left_button(0),
    m_right_button(0),
    m_left_right_button_layout(new Layout(0, 0, w, TabHeightFromFont(font), 1, 3)),
    m_text_color(text_color),
    m_style(style),
    m_first_tab_shown(0)
{
    SetColor(color);

    EnableChildClipping(true);

    boost::shared_ptr<StyleFactory> style_factory = GetStyleFactory();

    m_tabs = style_factory->NewRadioButtonGroup(0, 0, w, TabHeightFromFont(font), HORIZONTAL);
    m_tabs->ExpandButtons(true);
    m_tabs->ExpandButtonsProportionally(true);

    m_left_right_button_layout->SetColumnStretch(0, 1);
    m_left_right_button_layout->SetColumnStretch(1, 0);
    m_left_right_button_layout->SetColumnStretch(2, 0);

    m_left_button = style_factory->NewTabBarLeftButton(0, 0, BUTTON_WIDTH, Height(), "-", m_font, Color(), m_text_color);
    m_right_button = style_factory->NewTabBarRightButton(0, 0, BUTTON_WIDTH, Height(), "+", m_font, Color(), m_text_color);
    m_left_right_button_layout->SetMinimumColumnWidth(1, m_left_button->Width());
    m_left_right_button_layout->SetMinimumColumnWidth(2, m_right_button->Width());
    m_left_right_button_layout->Add(m_left_button, 0, 1);
    m_left_right_button_layout->Add(m_right_button, 0, 2);
    m_left_right_button_layout->Hide();

    AttachChild(m_tabs);
    AttachChild(m_left_right_button_layout);

    Connect(m_tabs->ButtonChangedSignal, &TabBar::TabChanged, this);
    Connect(m_left_button->ClickedSignal, &TabBar::LeftClicked, this);
    Connect(m_right_button->ClickedSignal, &TabBar::RightClicked, this);
}

Pt TabBar::MinUsableSize() const
{
    int y = 0;
    for (unsigned int i = 0; i < m_tab_buttons.size(); ++i) {
        int button_min_y = m_tab_buttons[i]->MinUsableSize().y;
        if (y < button_min_y)
            y = button_min_y;
    }
    return Pt(4 * BUTTON_WIDTH, y);
}

int TabBar::CurrentTab() const
{ return m_tabs->CheckedButton(); }

void TabBar::SizeMove(const Pt& ul, const Pt& lr)
{
    m_tabs->Resize(Pt(m_tabs->Size().x, lr.y -  ul.y));
    m_left_right_button_layout->SizeMove(Pt(0, 0), lr - ul);
    Control::SizeMove(ul, lr);
}

void TabBar::Render()
{}

void TabBar::AddTab(const std::string& name)
{ InsertTab(m_tab_buttons.size(), name); }

void TabBar::InsertTab(int index, const std::string& name)
{
    assert(0 <= index && index <= static_cast<int>(m_tab_buttons.size()));
    boost::shared_ptr<StyleFactory> style_factory = GetStyleFactory();
    StateButton* button = style_factory->NewTabBarTab(0, 0, 1, 1, name,
                                                      m_font, TF_CENTER, Color(),
                                                      m_text_color, CLR_ZERO,
                                                      m_style == TAB_BAR_ATTACHED ?
                                                      SBSTYLE_3D_TOP_ATTACHED_TAB :
                                                      SBSTYLE_3D_TOP_DETACHED_TAB);
    button->InstallEventFilter(this);
    m_tab_buttons.insert(m_tab_buttons.begin() + index, button);
    m_tabs->InsertButton(index, m_tab_buttons[index]);
    if (Width() < m_tabs->Width()) {
        m_left_right_button_layout->Show();
        m_left_button->Disable(m_first_tab_shown == 0);
        m_right_button->Disable(m_first_tab_shown == static_cast<int>(m_tab_buttons.size()) - 1);
    }
    if (m_tabs->CheckedButton() == RadioButtonGroup::NO_BUTTON)
        m_tabs->SetCheck(0);
}

void TabBar::RemoveTab(const std::string& name)
{
    int index = NO_TAB;
    for (unsigned int i = 0; i < m_tab_buttons.size(); ++i) {
        if (m_tab_buttons[i]->WindowText() == name) {
            index = i;
            break;
        }
    }
    assert(0 <= index && index < static_cast<int>(m_tab_buttons.size()));

    m_tab_buttons[index]->RemoveEventFilter(this);
    m_tabs->RemoveButton(m_tab_buttons[index]);
    delete m_tab_buttons[index];
    m_tab_buttons.erase(m_tab_buttons.begin() + index);
    if (m_tabs->Width() <= Width())
        m_left_right_button_layout->Hide();
    if (m_tabs->CheckedButton() == RadioButtonGroup::NO_BUTTON && !m_tab_buttons.empty())
        m_tabs->SetCheck(0);
}

void TabBar::SetCurrentTab(int index)
{ m_tabs->SetCheck(index); }

const Button* TabBar::LeftButton() const
{ return m_left_button; }

const Button* TabBar::RightButton() const
{ return m_right_button; }

void TabBar::DistinguishCurrentTab(const std::vector<StateButton*>& tab_buttons)
{ m_tabs->RaiseCheckedButton(); }

void TabBar::TabChanged(int index)
{
    if (index != RadioButtonGroup::NO_BUTTON) {
        BringTabIntoView(index);
        DistinguishCurrentTab(m_tab_buttons);
        TabChangedSignal(index);
    }
}

void TabBar::LeftClicked()
{
    assert(0 < m_first_tab_shown);
    m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[m_first_tab_shown - 1]->UpperLeft().x, 0));
    --m_first_tab_shown;
    m_left_button->Disable(m_first_tab_shown == 0);
    m_right_button->Disable(false);
}

void TabBar::RightClicked()
{
    assert(m_first_tab_shown < static_cast<int>(m_tab_buttons.size()) - 1);
    m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[m_first_tab_shown + 1]->UpperLeft().x, 0));
    ++m_first_tab_shown;
    m_right_button->Disable(m_first_tab_shown == static_cast<int>(m_tab_buttons.size()) - 1);
    m_left_button->Disable(false);
}

void TabBar::BringTabIntoView(int index)
{
    while (m_tab_buttons[index]->UpperLeft().x < UpperLeft().x) {
        LeftClicked();
    }
    if (m_tab_buttons[index]->Width() < Width()) {
        int right_side = m_left_right_button_layout->Visible() ?
            m_left_button->UpperLeft().x :
            LowerRight().x;
        while (right_side < m_tab_buttons[index]->LowerRight().x && index != m_first_tab_shown) {
            RightClicked();
        }
    } else {
        m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[index]->UpperLeft().x, 0));
        m_right_button->Disable(m_first_tab_shown == static_cast<int>(m_tab_buttons.size()) - 1);
        m_left_button->Disable(false);
    }
}

bool TabBar::EventFilter(Wnd* w, const Event& event)
{
    if (event.Type() == Event::LButtonDown ||
        event.Type() == Event::RButtonDown)
        MoveChildUp(m_left_right_button_layout);
    return false;
}
<commit_msg>Modified the right-button-disable behavior of TabBar.  Now, the tabs can be scrolled right only until the last one is in view, instead of until the last one is in the leftmost position.<commit_after>/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003 T. Zachary Laine

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

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

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.

   Zach Laine
   whatwasthataddress@hotmail.com */

/* $Id: Edit.cpp 528 2006-03-04 02:56:33Z tzlaine $ */

#include <GG/TabWnd.h>

#ifndef _GG_DrawUtil_h_
#include <GG/DrawUtil.h>
#endif

#ifndef _GG_Layout_h_
#include <GG/Layout.h>
#endif

#ifndef _GG_StyleFactory_h_
#include <GG/StyleFactory.h>
#endif

using namespace GG;

namespace {
    int TabHeightFromFont(const boost::shared_ptr<Font>& font)
    { return font->Lineskip() + 10; }
}

////////////////////////////////////////////////
// GG::TabWnd
////////////////////////////////////////////////
// static(s)
const int TabWnd::NO_WND = RadioButtonGroup::NO_BUTTON;

TabWnd::TabWnd() :
    m_tab_bar(0),
    m_current_wnd(0)
{}

TabWnd::~TabWnd()
{
    for (unsigned int i = 0; i < m_wnds.size(); ++i) {
        delete m_wnds[i].first;
    }
}

TabWnd::TabWnd(int x, int y, int w, int h, const boost::shared_ptr<Font>& font, Clr color, Clr text_color/* = CLR_BLACK*/,
               TabBarStyle style/* = TAB_BAR_ATTACHED*/, Uint32 flags/* = CLICKABLE | DRAGABLE*/) :
    Wnd(x, y, w, h, flags),
    m_tab_bar(GetStyleFactory()->NewTabBar(0, 0, w, font, color, text_color, style, CLICKABLE)),
    m_current_wnd(0)
{
    Layout* layout = new Layout(0, 0, w, h, 2, 1);
    layout->SetRowStretch(1, 1.0);
    layout->Add(m_tab_bar, 0, 0);
    SetLayout(layout);
    Connect(m_tab_bar->TabChangedSignal, &TabWnd::TabChanged, this);
}

Pt TabWnd::MinUsableSize() const
{
    Pt retval = m_tab_bar->MinUsableSize();
    retval.y *= 2;
    return retval;
}

int TabWnd::CurrentWnd() const
{ return m_tab_bar->CurrentTab(); }

void TabWnd::Render()
{}

void TabWnd::AddWnd(Wnd* wnd, const std::string& name)
{ InsertWnd(m_wnds.size(), wnd, name); }

void TabWnd::InsertWnd(int index, Wnd* wnd, const std::string& name)
{
    m_wnds.insert(m_wnds.begin() + index, std::make_pair(wnd, name));
    m_tab_bar->InsertTab(index, name);
    GetLayout()->SetMinimumRowHeight(0, m_tab_bar->MinUsableSize().y + 2 * 5);
}

Wnd* TabWnd::RemoveWnd(const std::string& name)
{
    Wnd* retval = 0;
    int index = NO_WND;
    for (unsigned int i = 0; i < m_wnds.size(); ++i) {
        if (m_wnds[i].second == name) {
            index = i;
            break;
        }
    }
    if (index != NO_WND) {
        retval = m_wnds[index].first;
        m_wnds.erase(m_wnds.begin() + index);
        m_tab_bar->RemoveTab(name);
        GetLayout()->SetMinimumRowHeight(0, m_tab_bar->MinUsableSize().y + 2 * 5);
    }
    return retval;
}

void TabWnd::SetCurrentWnd(int index)
{ m_tab_bar->SetCurrentTab(index); }

const TabBar* TabWnd::GetTabBar() const
{ return m_tab_bar; }

const std::vector<std::pair<Wnd*, std::string> >& TabWnd::Wnds() const
{ return m_wnds; }

void TabWnd::TabChanged(int index)
{
    assert(0 <= index && index < static_cast<int>(m_wnds.size()));
    Wnd* old_current_wnd = m_current_wnd;
    m_current_wnd = m_wnds[index].first;
    if (m_current_wnd != old_current_wnd) {
        Layout* layout = GetLayout();
        layout->Remove(old_current_wnd);
        layout->Add(m_current_wnd, 1, 0);
    }
    WndChangedSignal(index);
}

////////////////////////////////////////////////
// GG::TabBar
////////////////////////////////////////////////
// static(s)
const int TabBar::NO_TAB = TabWnd::NO_WND;
const int TabBar::BUTTON_WIDTH = 10;

TabBar::TabBar() :
    Control(),
    m_tabs(0),
    m_left_button(0),
    m_right_button(0),
    m_left_right_button_layout(0),
    m_text_color(CLR_BLACK),
    m_style(TAB_BAR_ATTACHED),
    m_first_tab_shown(0)
{}

TabBar::TabBar(int x, int y, int w, const boost::shared_ptr<Font>& font, Clr color, Clr text_color/* = CLR_BLACK*/,
               TabBarStyle style/* = TAB_BAR_ATTACHED*/, Uint32 flags/* = CLICKABLE*/) :
    Control(x, y, w, TabHeightFromFont(font), flags),
    m_tabs(0),
    m_font(font),
    m_left_button(0),
    m_right_button(0),
    m_left_right_button_layout(new Layout(0, 0, w, TabHeightFromFont(font), 1, 3)),
    m_text_color(text_color),
    m_style(style),
    m_first_tab_shown(0)
{
    SetColor(color);

    EnableChildClipping(true);

    boost::shared_ptr<StyleFactory> style_factory = GetStyleFactory();

    m_tabs = style_factory->NewRadioButtonGroup(0, 0, w, TabHeightFromFont(font), HORIZONTAL);
    m_tabs->ExpandButtons(true);
    m_tabs->ExpandButtonsProportionally(true);

    m_left_right_button_layout->SetColumnStretch(0, 1);
    m_left_right_button_layout->SetColumnStretch(1, 0);
    m_left_right_button_layout->SetColumnStretch(2, 0);

    m_left_button = style_factory->NewTabBarLeftButton(0, 0, BUTTON_WIDTH, Height(), "-", m_font, Color(), m_text_color);
    m_right_button = style_factory->NewTabBarRightButton(0, 0, BUTTON_WIDTH, Height(), "+", m_font, Color(), m_text_color);
    m_left_right_button_layout->SetMinimumColumnWidth(1, m_left_button->Width());
    m_left_right_button_layout->SetMinimumColumnWidth(2, m_right_button->Width());
    m_left_right_button_layout->Add(m_left_button, 0, 1);
    m_left_right_button_layout->Add(m_right_button, 0, 2);
    m_left_right_button_layout->Hide();

    AttachChild(m_tabs);
    AttachChild(m_left_right_button_layout);

    Connect(m_tabs->ButtonChangedSignal, &TabBar::TabChanged, this);
    Connect(m_left_button->ClickedSignal, &TabBar::LeftClicked, this);
    Connect(m_right_button->ClickedSignal, &TabBar::RightClicked, this);
}

Pt TabBar::MinUsableSize() const
{
    int y = 0;
    for (unsigned int i = 0; i < m_tab_buttons.size(); ++i) {
        int button_min_y = m_tab_buttons[i]->MinUsableSize().y;
        if (y < button_min_y)
            y = button_min_y;
    }
    return Pt(4 * BUTTON_WIDTH, y);
}

int TabBar::CurrentTab() const
{ return m_tabs->CheckedButton(); }

void TabBar::SizeMove(const Pt& ul, const Pt& lr)
{
    m_tabs->Resize(Pt(m_tabs->Size().x, lr.y -  ul.y));
    m_left_right_button_layout->SizeMove(Pt(0, 0), lr - ul);
    Control::SizeMove(ul, lr);
}

void TabBar::Render()
{}

void TabBar::AddTab(const std::string& name)
{ InsertTab(m_tab_buttons.size(), name); }

void TabBar::InsertTab(int index, const std::string& name)
{
    assert(0 <= index && index <= static_cast<int>(m_tab_buttons.size()));
    boost::shared_ptr<StyleFactory> style_factory = GetStyleFactory();
    StateButton* button = style_factory->NewTabBarTab(0, 0, 1, 1, name,
                                                      m_font, TF_CENTER, Color(),
                                                      m_text_color, CLR_ZERO,
                                                      m_style == TAB_BAR_ATTACHED ?
                                                      SBSTYLE_3D_TOP_ATTACHED_TAB :
                                                      SBSTYLE_3D_TOP_DETACHED_TAB);
    button->InstallEventFilter(this);
    m_tab_buttons.insert(m_tab_buttons.begin() + index, button);
    m_tabs->InsertButton(index, m_tab_buttons[index]);
    if (Width() < m_tabs->Width()) {
        m_left_right_button_layout->Show();
        m_left_button->Disable(m_first_tab_shown == 0);
        int right_side = m_left_right_button_layout->Visible() ?
            m_left_button->UpperLeft().x :
            LowerRight().x;
        m_right_button->Disable(m_tab_buttons.back()->LowerRight().x <= right_side);
    }
    if (m_tabs->CheckedButton() == RadioButtonGroup::NO_BUTTON)
        m_tabs->SetCheck(0);
}

void TabBar::RemoveTab(const std::string& name)
{
    int index = NO_TAB;
    for (unsigned int i = 0; i < m_tab_buttons.size(); ++i) {
        if (m_tab_buttons[i]->WindowText() == name) {
            index = i;
            break;
        }
    }
    assert(0 <= index && index < static_cast<int>(m_tab_buttons.size()));

    m_tab_buttons[index]->RemoveEventFilter(this);
    m_tabs->RemoveButton(m_tab_buttons[index]);
    delete m_tab_buttons[index];
    m_tab_buttons.erase(m_tab_buttons.begin() + index);
    if (m_tabs->Width() <= Width())
        m_left_right_button_layout->Hide();
    if (m_tabs->CheckedButton() == RadioButtonGroup::NO_BUTTON && !m_tab_buttons.empty())
        m_tabs->SetCheck(0);
}

void TabBar::SetCurrentTab(int index)
{ m_tabs->SetCheck(index); }

const Button* TabBar::LeftButton() const
{ return m_left_button; }

const Button* TabBar::RightButton() const
{ return m_right_button; }

void TabBar::DistinguishCurrentTab(const std::vector<StateButton*>& tab_buttons)
{ m_tabs->RaiseCheckedButton(); }

void TabBar::TabChanged(int index)
{
    if (index != RadioButtonGroup::NO_BUTTON) {
        BringTabIntoView(index);
        DistinguishCurrentTab(m_tab_buttons);
        TabChangedSignal(index);
    }
}

void TabBar::LeftClicked()
{
    assert(0 < m_first_tab_shown);
    m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[m_first_tab_shown - 1]->UpperLeft().x, 0));
    --m_first_tab_shown;
    m_left_button->Disable(m_first_tab_shown == 0);
    m_right_button->Disable(false);
}

void TabBar::RightClicked()
{
    assert(m_first_tab_shown < static_cast<int>(m_tab_buttons.size()) - 1);
    m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[m_first_tab_shown + 1]->UpperLeft().x, 0));
    ++m_first_tab_shown;
    int right_side = m_left_right_button_layout->Visible() ?
        m_left_button->UpperLeft().x :
        LowerRight().x;
    m_right_button->Disable(m_tab_buttons.back()->LowerRight().x <= right_side);
    m_left_button->Disable(false);
}

void TabBar::BringTabIntoView(int index)
{
    while (m_tab_buttons[index]->UpperLeft().x < UpperLeft().x) {
        LeftClicked();
    }
    int right_side = m_left_right_button_layout->Visible() ?
        m_left_button->UpperLeft().x :
        LowerRight().x;
    if (m_tab_buttons[index]->Width() < Width()) {
        while (right_side < m_tab_buttons[index]->LowerRight().x && index != m_first_tab_shown) {
            RightClicked();
        }
    } else {
        m_tabs->OffsetMove(Pt(m_tab_buttons[m_first_tab_shown]->UpperLeft().x - m_tab_buttons[index]->UpperLeft().x, 0));
        m_right_button->Disable(m_tab_buttons.back()->LowerRight().x <= right_side);
        m_left_button->Disable(false);
    }
}

bool TabBar::EventFilter(Wnd* w, const Event& event)
{
    if (event.Type() == Event::LButtonDown ||
        event.Type() == Event::RButtonDown)
        MoveChildUp(m_left_right_button_layout);
    return false;
}
<|endoftext|>


<commit_before>
#include "Wrenly.h"
#include "File.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp
#include <iostream>
#include <cstdio>

namespace {

    std::unordered_map< std::size_t, WrenForeignMethodFn >* boundForeignMethods{ nullptr };
    std::unordered_map< std::size_t, WrenForeignClassMethods >* boundForeignClasses{ nullptr };

    /*
     * This function is going to use a global pointer to a bound method tree.
     *
     * When the correspodning wren vm executes a module, it has to bind its instances
     * of the bound method/class tree to the global variable.
     *
     * There is no way to avoid this static/global function
     * */
    WrenForeignMethodFn ForeignMethodProvider( WrenVM* vm,
                                 const char* module,
                                 const char* className,
                                 bool isStatic,
                                 const char* signature ) {
        if ( !boundForeignMethods ) {
            return NULL;
        }
        auto it = boundForeignMethods->find( wrenly::detail::HashMethodSignature( module, className, isStatic, signature ) );
        if ( it == boundForeignMethods->end() ) {
            return NULL;
        }

        return it->second;
    }

    WrenForeignClassMethods ForeignClassProvider( WrenVM* vm, const char* m, const char* c ) {
        if ( !boundForeignClasses ) {
            return WrenForeignClassMethods{ nullptr, nullptr };
        }
        auto it = boundForeignClasses->find( wrenly::detail::HashClassSignature( m, c ) );
        if ( it == boundForeignClasses->end() ) {
            return WrenForeignClassMethods{ nullptr, nullptr };
        }

        return it->second;
    }

    char* LoadModuleFnWrapper( WrenVM* vm, const char* mod ) {
        return wrenly::Wren::loadModuleFn( mod );
    }

    void WriteFnWrapper( WrenVM* vm, const char* text ) {
        wrenly::Wren::writeFn( vm, text );
    }
}

namespace wrenly {

Method::Method( WrenVM* vm, WrenValue* method )
:   vm_( vm ),
    method_( method ),
    refCount_( nullptr ) {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Method::Method( const Method& other )
:   vm_( other.vm_ ),
    method_( other.method_ ),
    refCount_( other.refCount_ ) {
    retain_();
}

Method::Method( Method&& other )
:   vm_( other.vm_ ),
    method_( other.method_ ),
    refCount_( other.refCount_ ) {
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.refCount_ = nullptr;
}

Method::~Method() {
    release_();
}

Method& Method::operator=( Method rhs ) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

void Method::retain_() {
    *refCount_ += 1u;
}

void Method::release_() {
    if ( refCount_ ) {
        *refCount_ -= 1u;
        if ( *refCount_ == 0u ) {
            wrenReleaseValue( vm_, method_ );
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

ModuleContext::ModuleContext( std::string module, Wren* wren )
:   wren_( wren ),
    module_( module )
    {}

ClassContext ModuleContext::beginClass( std::string c ) {
    return ClassContext( c, wren_, this );
}

void ModuleContext::endModule() {}

ClassContext::ClassContext( std::string c, Wren* wren, ModuleContext* mod )
:   wren_( wren ),
    module_( mod ),
    class_( c )
    {}

ModuleContext& ClassContext::endClass() {
    return *module_;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn Wren::loadModuleFn = []( const char* mod ) -> char* {
    std::string path( mod );
    path += ".wren";
    std::string source;
    try {
        source = wrenly::FileToString( path );
    } catch( const std::exception& e ) {
        return NULL;
    }
    char* buffer = (char*) malloc( source.size() );
    memcpy( buffer, source.c_str(), source.size() );
    return buffer;
};

WriteFn Wren::writeFn = []( WrenVM* vm, const char* text ) -> void {
    printf( text );
};

Wren::Wren()
:   vm_( nullptr ),
    foreignMethods_() {

    WrenConfiguration configuration{};
    wrenInitConfiguration( &configuration );
    configuration.bindForeignMethodFn = ForeignMethodProvider;
    configuration.loadModuleFn = LoadModuleFnWrapper;
    configuration.bindForeignClassFn = ForeignClassProvider;
    configuration.writeFn = WriteFnWrapper;
    vm_ = wrenNewVM( &configuration );
}

Wren::Wren( Wren&& other )
:   vm_( other.vm_ ),
    foreignMethods_( std::move( other.foreignMethods_ ) ),
    foreignClasses_( std::move( other.foreignClasses_ ) ){
    other.vm_ = nullptr;
}

Wren& Wren::operator=( Wren&& rhs ) {
    vm_             = rhs.vm_;
    foreignMethods_ = std::move( rhs.foreignMethods_ );
    foreignClasses_ = std::move( rhs.foreignClasses_ );
    rhs.vm_         = nullptr;
    return *this;
}

Wren::~Wren() {
    wrenFreeVM( vm_ );
}

WrenVM* Wren::vm() {
    return vm_;
}

void Wren::executeModule( const std::string& mod ) {
    // set global variables for the C-callbacks
    boundForeignMethods = &foreignMethods_;
    boundForeignClasses = &foreignClasses_;

    std::string file = mod;
    file += ".wren";
    auto source = FileToString( file );
    auto res = wrenInterpret( vm_, file.c_str(), source.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        std::cerr << "WREN_RESULT_COMPILE_ERROR in module " << mod << std::endl;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        std::cerr << "WREN_RESULT_RUNTIME_ERROR in module " << mod << std::endl;
    }

    boundForeignMethods = nullptr;
    boundForeignClasses = nullptr;
}

void Wren::executeString( const std::string& code ) {
    // set global variables for the C-callbacks
    boundForeignMethods = &foreignMethods_;
    boundForeignClasses = &foreignClasses_;

    auto res = wrenInterpret( vm_, "string", code.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        std::cerr << "WREN_RESULT_COMPILE_ERROR in string: " << code << std::endl;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        std::cerr << "WREN_RESULT_RUNTIME_ERROR in string: " << code << std::endl;
    }

    boundForeignMethods = nullptr;
    boundForeignClasses = nullptr;
}

void Wren::collectGarbage() {
    wrenCollectGarbage( vm_ );
}

ModuleContext Wren::beginModule( std::string mod ) {
    return ModuleContext( mod, this );
}

Method Wren::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
) {
    return Method( vm_, wrenGetMethod( vm_, mod.c_str(), var.c_str(), sig.c_str() ) );
}

void Wren::registerFunction_(
    const std::string& mod,
    const std::string& cName,
    bool isStatic,
    const std::string& sig,
    WrenForeignMethodFn function
) {
    std::size_t hash = detail::HashMethodSignature( mod.c_str(), cName.c_str(), isStatic, sig.c_str() );
    foreignMethods_.insert( std::make_pair( hash, function ) );
}

void Wren::registerClass_(
    const std::string& m,
    const std::string& c,
    WrenForeignClassMethods methods
) {
    std::size_t hash = detail::HashClassSignature( m.c_str(), c.c_str() );
    foreignClasses_.insert( std::make_pair( hash, methods ) );
}

}   // wrenly
<commit_msg>fix warning in the printFn closure<commit_after>
#include "Wrenly.h"
#include "File.h"
#include <cstdlib>  // for malloc
#include <cstring>  // for strcmp
#include <iostream>
#include <cstdio>

namespace {

    std::unordered_map< std::size_t, WrenForeignMethodFn >* boundForeignMethods{ nullptr };
    std::unordered_map< std::size_t, WrenForeignClassMethods >* boundForeignClasses{ nullptr };

    /*
     * This function is going to use a global pointer to a bound method tree.
     *
     * When the correspodning wren vm executes a module, it has to bind its instances
     * of the bound method/class tree to the global variable.
     *
     * There is no way to avoid this static/global function
     * */
    WrenForeignMethodFn ForeignMethodProvider( WrenVM* vm,
                                 const char* module,
                                 const char* className,
                                 bool isStatic,
                                 const char* signature ) {
        if ( !boundForeignMethods ) {
            return NULL;
        }
        auto it = boundForeignMethods->find( wrenly::detail::HashMethodSignature( module, className, isStatic, signature ) );
        if ( it == boundForeignMethods->end() ) {
            return NULL;
        }

        return it->second;
    }

    WrenForeignClassMethods ForeignClassProvider( WrenVM* vm, const char* m, const char* c ) {
        if ( !boundForeignClasses ) {
            return WrenForeignClassMethods{ nullptr, nullptr };
        }
        auto it = boundForeignClasses->find( wrenly::detail::HashClassSignature( m, c ) );
        if ( it == boundForeignClasses->end() ) {
            return WrenForeignClassMethods{ nullptr, nullptr };
        }

        return it->second;
    }

    char* LoadModuleFnWrapper( WrenVM* vm, const char* mod ) {
        return wrenly::Wren::loadModuleFn( mod );
    }

    void WriteFnWrapper( WrenVM* vm, const char* text ) {
        wrenly::Wren::writeFn( vm, text );
    }
}

namespace wrenly {

Method::Method( WrenVM* vm, WrenValue* method )
:   vm_( vm ),
    method_( method ),
    refCount_( nullptr ) {
    refCount_ = new unsigned;
    *refCount_ = 1u;
}

Method::Method( const Method& other )
:   vm_( other.vm_ ),
    method_( other.method_ ),
    refCount_( other.refCount_ ) {
    retain_();
}

Method::Method( Method&& other )
:   vm_( other.vm_ ),
    method_( other.method_ ),
    refCount_( other.refCount_ ) {
    other.vm_ = nullptr;
    other.method_ = nullptr;
    other.refCount_ = nullptr;
}

Method::~Method() {
    release_();
}

Method& Method::operator=( Method rhs ) {
    release_();
    vm_ = rhs.vm_;
    method_ = rhs.method_;
    refCount_ = rhs.refCount_;
    retain_();
    return *this;
}

void Method::retain_() {
    *refCount_ += 1u;
}

void Method::release_() {
    if ( refCount_ ) {
        *refCount_ -= 1u;
        if ( *refCount_ == 0u ) {
            wrenReleaseValue( vm_, method_ );
            delete refCount_;
            refCount_ = nullptr;
        }
    }
}

ModuleContext::ModuleContext( std::string module, Wren* wren )
:   wren_( wren ),
    module_( module )
    {}

ClassContext ModuleContext::beginClass( std::string c ) {
    return ClassContext( c, wren_, this );
}

void ModuleContext::endModule() {}

ClassContext::ClassContext( std::string c, Wren* wren, ModuleContext* mod )
:   wren_( wren ),
    module_( mod ),
    class_( c )
    {}

ModuleContext& ClassContext::endClass() {
    return *module_;
}

/*
 * Returns the source as a heap-allocated string.
 * Uses malloc, because our reallocateFn is set to default:
 * it uses malloc, realloc and free.
 * */
LoadModuleFn Wren::loadModuleFn = []( const char* mod ) -> char* {
    std::string path( mod );
    path += ".wren";
    std::string source;
    try {
        source = wrenly::FileToString( path );
    } catch( const std::exception& e ) {
        return NULL;
    }
    char* buffer = (char*) malloc( source.size() );
    memcpy( buffer, source.c_str(), source.size() );
    return buffer;
};

WriteFn Wren::writeFn = []( WrenVM* vm, const char* text ) -> void {
    printf( "%s", text );
};

Wren::Wren()
:   vm_( nullptr ),
    foreignMethods_() {

    WrenConfiguration configuration{};
    wrenInitConfiguration( &configuration );
    configuration.bindForeignMethodFn = ForeignMethodProvider;
    configuration.loadModuleFn = LoadModuleFnWrapper;
    configuration.bindForeignClassFn = ForeignClassProvider;
    configuration.writeFn = WriteFnWrapper;
    vm_ = wrenNewVM( &configuration );
}

Wren::Wren( Wren&& other )
:   vm_( other.vm_ ),
    foreignMethods_( std::move( other.foreignMethods_ ) ),
    foreignClasses_( std::move( other.foreignClasses_ ) ){
    other.vm_ = nullptr;
}

Wren& Wren::operator=( Wren&& rhs ) {
    vm_             = rhs.vm_;
    foreignMethods_ = std::move( rhs.foreignMethods_ );
    foreignClasses_ = std::move( rhs.foreignClasses_ );
    rhs.vm_         = nullptr;
    return *this;
}

Wren::~Wren() {
    wrenFreeVM( vm_ );
}

WrenVM* Wren::vm() {
    return vm_;
}

void Wren::executeModule( const std::string& mod ) {
    // set global variables for the C-callbacks
    boundForeignMethods = &foreignMethods_;
    boundForeignClasses = &foreignClasses_;

    std::string file = mod;
    file += ".wren";
    auto source = FileToString( file );
    auto res = wrenInterpret( vm_, file.c_str(), source.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        std::cerr << "WREN_RESULT_COMPILE_ERROR in module " << mod << std::endl;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        std::cerr << "WREN_RESULT_RUNTIME_ERROR in module " << mod << std::endl;
    }

    boundForeignMethods = nullptr;
    boundForeignClasses = nullptr;
}

void Wren::executeString( const std::string& code ) {
    // set global variables for the C-callbacks
    boundForeignMethods = &foreignMethods_;
    boundForeignClasses = &foreignClasses_;

    auto res = wrenInterpret( vm_, "string", code.c_str() );

    if ( res == WrenInterpretResult::WREN_RESULT_COMPILE_ERROR ) {
        std::cerr << "WREN_RESULT_COMPILE_ERROR in string: " << code << std::endl;
    }

    if ( res == WrenInterpretResult::WREN_RESULT_RUNTIME_ERROR ) {
        std::cerr << "WREN_RESULT_RUNTIME_ERROR in string: " << code << std::endl;
    }

    boundForeignMethods = nullptr;
    boundForeignClasses = nullptr;
}

void Wren::collectGarbage() {
    wrenCollectGarbage( vm_ );
}

ModuleContext Wren::beginModule( std::string mod ) {
    return ModuleContext( mod, this );
}

Method Wren::method(
    const std::string& mod,
    const std::string& var,
    const std::string& sig
) {
    return Method( vm_, wrenGetMethod( vm_, mod.c_str(), var.c_str(), sig.c_str() ) );
}

void Wren::registerFunction_(
    const std::string& mod,
    const std::string& cName,
    bool isStatic,
    const std::string& sig,
    WrenForeignMethodFn function
) {
    std::size_t hash = detail::HashMethodSignature( mod.c_str(), cName.c_str(), isStatic, sig.c_str() );
    foreignMethods_.insert( std::make_pair( hash, function ) );
}

void Wren::registerClass_(
    const std::string& m,
    const std::string& c,
    WrenForeignClassMethods methods
) {
    std::size_t hash = detail::HashClassSignature( m.c_str(), c.c_str() );
    foreignClasses_.insert( std::make_pair( hash, methods ) );
}

}   // wrenly
<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <map>
#include <vector>

#include "common.hxx"
#include "realm.hxx"
#include "advert.hxx"

using namespace std;

static realmed<map<asio::ip::udp::endpoint, Advert*> > adverts;

Advert::Advert(const Realm* r, const asio::ip::udp::endpoint& ep)
: realm(r), endpoint(ep)
{
  adverts[r][ep] = this;
}

Advert::Advert(const Advert& that)
: realm(that.realm), endpoint(that.endpoint)
{
  adverts[realm][endpoint] = this;
}

Advert::~Advert() {
  map<asio::ip::udp::endpoint,Advert*>::iterator it =
    adverts[realm].find(endpoint);
  if (it != adverts[realm].end() && it->second == this)
    adverts[realm].erase(it);
}

void Advert::setData(const byte* dat, unsigned len) {
  data.assign(dat, dat+len);
}

Advert::iterator::iterator(const Realm* r)
: realm(r), beginning(true)
{ }

Advert::iterator::iterator(const iterator& that)
: realm(that.realm), prev(that.prev), beginning(that.beginning)
{ }

Advert::iterator& Advert::iterator::operator=(const iterator& that) {
  realm = that.realm;
  prev = that.prev;
  beginning = that.beginning;
  return *this;
}

bool Advert::iterator::next(asio::ip::udp::endpoint& ep, vector<byte>& dst) {
  map<asio::ip::udp::endpoint,Advert*>::const_iterator it =
    beginning? adverts[realm].begin() : adverts[realm].lower_bound(prev);
  //Move past the key (we got this last time)
  if (beginning && it != adverts[realm].end())
    ++it;
  beginning = false;

  //Move past any empty ones
  while (it != adverts[realm].end() && it->second->data.empty())
    ++it;

  if (it != adverts[realm].end()) {
    ep = it->second->endpoint;
    dst.insert(dst.end(), it->second->data.begin(), it->second->data.end());
    prev = ep;
    return true;
  } else {
    return false;
  }
}

void Advert::iterator::reset() {
  beginning = true;
}
<commit_msg>Fix Advert::iterator::next().<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <map>
#include <vector>

#include "common.hxx"
#include "realm.hxx"
#include "advert.hxx"

using namespace std;

static realmed<map<asio::ip::udp::endpoint, Advert*> > adverts;

Advert::Advert(const Realm* r, const asio::ip::udp::endpoint& ep)
: realm(r), endpoint(ep)
{
  adverts[r][ep] = this;
}

Advert::Advert(const Advert& that)
: realm(that.realm), endpoint(that.endpoint)
{
  adverts[realm][endpoint] = this;
}

Advert::~Advert() {
  map<asio::ip::udp::endpoint,Advert*>::iterator it =
    adverts[realm].find(endpoint);
  if (it != adverts[realm].end() && it->second == this)
    adverts[realm].erase(it);
}

void Advert::setData(const byte* dat, unsigned len) {
  data.assign(dat, dat+len);
}

Advert::iterator::iterator(const Realm* r)
: realm(r), beginning(true)
{ }

Advert::iterator::iterator(const iterator& that)
: realm(that.realm), prev(that.prev), beginning(that.beginning)
{ }

Advert::iterator& Advert::iterator::operator=(const iterator& that) {
  realm = that.realm;
  prev = that.prev;
  beginning = that.beginning;
  return *this;
}

bool Advert::iterator::next(asio::ip::udp::endpoint& ep, vector<byte>& dst) {
  map<asio::ip::udp::endpoint,Advert*>::const_iterator it =
    beginning? adverts[realm].begin() : adverts[realm].lower_bound(prev);
  //Move past the key (we got this last time)
  if (!beginning && it != adverts[realm].end())
    ++it;
  beginning = false;

  //Move past any empty ones
  while (it != adverts[realm].end() && it->second->data.empty())
    ++it;

  if (it != adverts[realm].end()) {
    ep = it->second->endpoint;
    dst.insert(dst.end(), it->second->data.begin(), it->second->data.end());
    prev = ep;
    return true;
  } else {
    return false;
  }
}

void Advert::iterator::reset() {
  beginning = true;
}
<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#ifdef TORRENT_DEBUG

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifdef __GNUC__

#include <cxxabi.h>
#include <string>
#include <cstring>
#include <stdlib.h>

std::string demangle(char const* name)
{
// in case this string comes
	// this is needed on linux
	char const* start = strchr(name, '(');
	if (start != 0)
	{
		++start;
	}
	else
	{
		// this is needed on macos x
		start = strstr(name, "0x");
		if (start != 0)
		{
			start = strchr(start, ' ');
			if (start != 0) ++start;
			else start = name;
		}
		else start = name;
	}

	char const* end = strchr(start, '+');
	if (end) while (*(end-1) == ' ') --end;

	std::string in;
	if (end == 0) in.assign(start);
	else in.assign(start, end);

	size_t len;
	int status;
	char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status);
	if (unmangled == 0) return in;
	std::string ret(unmangled);
	free(unmangled);
	return ret;
}

#endif

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "libtorrent/version.hpp"

// execinfo.h is available in the MacOS X 10.5 SDK.
#if (defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
#include <execinfo.h>

void print_backtrace(char const* label)
{
	void* stack[50];
	int size = backtrace(stack, 50);
	char** symbols = backtrace_symbols(stack, size);

	fprintf(stderr, "%s\n", label);
	for (int i = 1; i < size; ++i)
	{
		fprintf(stderr, "%d: %s\n", i, demangle(symbols[i]).c_str());
	}

	free(symbols);
}
#else

void print_backtrace(char const* label) {}

#endif

void assert_fail(char const* expr, int line, char const* file, char const* function)
{

	fprintf(stderr, "assertion failed. Please file a bugreport at "
		"http://code.rasterbar.com/libtorrent/newticket\n"
		"Please include the following information:\n\n"
		"version: " LIBTORRENT_VERSION "\n"
		"%s"
		"file: '%s'\n"
		"line: %d\n"
		"function: %s\n"
		"expression: %s\n", LIBTORRENT_REVISION, file, line, function, expr);

	print_backtrace("stack:");

 	// send SIGINT to the current process
 	// to break into the debugger
 	raise(SIGINT);
 	abort();
}

#else

void assert_fail(char const* expr, int line, char const* file, char const* function) {}

#endif

<commit_msg>fixed missing new line in assert message<commit_after>/*

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

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

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

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

*/

#ifdef TORRENT_DEBUG

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifdef __GNUC__

#include <cxxabi.h>
#include <string>
#include <cstring>
#include <stdlib.h>

std::string demangle(char const* name)
{
// in case this string comes
	// this is needed on linux
	char const* start = strchr(name, '(');
	if (start != 0)
	{
		++start;
	}
	else
	{
		// this is needed on macos x
		start = strstr(name, "0x");
		if (start != 0)
		{
			start = strchr(start, ' ');
			if (start != 0) ++start;
			else start = name;
		}
		else start = name;
	}

	char const* end = strchr(start, '+');
	if (end) while (*(end-1) == ' ') --end;

	std::string in;
	if (end == 0) in.assign(start);
	else in.assign(start, end);

	size_t len;
	int status;
	char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status);
	if (unmangled == 0) return in;
	std::string ret(unmangled);
	free(unmangled);
	return ret;
}

#endif

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "libtorrent/version.hpp"

// execinfo.h is available in the MacOS X 10.5 SDK.
#if (defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
#include <execinfo.h>

void print_backtrace(char const* label)
{
	void* stack[50];
	int size = backtrace(stack, 50);
	char** symbols = backtrace_symbols(stack, size);

	fprintf(stderr, "%s\n", label);
	for (int i = 1; i < size; ++i)
	{
		fprintf(stderr, "%d: %s\n", i, demangle(symbols[i]).c_str());
	}

	free(symbols);
}
#else

void print_backtrace(char const* label) {}

#endif

void assert_fail(char const* expr, int line, char const* file, char const* function)
{

	fprintf(stderr, "assertion failed. Please file a bugreport at "
		"http://code.rasterbar.com/libtorrent/newticket\n"
		"Please include the following information:\n\n"
		"version: " LIBTORRENT_VERSION "\n"
		"%s\n"
		"file: '%s'\n"
		"line: %d\n"
		"function: %s\n"
		"expression: %s\n", LIBTORRENT_REVISION, file, line, function, expr);

	print_backtrace("stack:");

 	// send SIGINT to the current process
 	// to break into the debugger
 	raise(SIGINT);
 	abort();
}

#else

void assert_fail(char const* expr, int line, char const* file, char const* function) {}

#endif

<|endoftext|>


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

#include <banman.h>

#include <netaddress.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/time.h>

BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
{
    if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist..."));

    int64_t nStart = GetTimeMillis();
    m_is_dirty = false;
    banmap_t banmap;
    if (m_ban_db.Read(banmap)) {
        SetBanned(banmap);        // thread save setter
        SetBannedSetDirty(false); // no need to write down, just read data
        SweepBanned();            // sweep out unused entries

        LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat  %dms\n",
            banmap.size(), GetTimeMillis() - nStart);
    } else {
        LogPrintf("Invalid or missing banlist.dat; recreating\n");
        SetBannedSetDirty(true); // force write
        DumpBanlist();
    }
}

BanMan::~BanMan()
{
    DumpBanlist();
}

void BanMan::DumpBanlist()
{
    SweepBanned(); // clean unused entries (if bantime has expired)

    if (!BannedSetIsDirty()) return;

    int64_t nStart = GetTimeMillis();

    banmap_t banmap;
    GetBanned(banmap);
    if (m_ban_db.Write(banmap)) {
        SetBannedSetDirty(false);
    }

    LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat  %dms\n",
        banmap.size(), GetTimeMillis() - nStart);
}

void BanMan::ClearBanned()
{
    {
        LOCK(m_cs_banned);
        m_banned.clear();
        m_is_dirty = true;
    }
    DumpBanlist(); //store banlist to disk
    if (m_client_interface) m_client_interface->BannedListChanged();
}

bool BanMan::IsBanned(CNetAddr netAddr)
{
    LOCK(m_cs_banned);
    for (const auto& it : m_banned) {
        CSubNet subNet = it.first;
        CBanEntry banEntry = it.second;

        if (subNet.Match(netAddr) && GetTime() < banEntry.nBanUntil) {
            return true;
        }
    }
    return false;
}

bool BanMan::IsBanned(CSubNet subNet)
{
    LOCK(m_cs_banned);
    banmap_t::iterator i = m_banned.find(subNet);
    if (i != m_banned.end()) {
        CBanEntry banEntry = (*i).second;
        if (GetTime() < banEntry.nBanUntil) {
            return true;
        }
    }
    return false;
}

void BanMan::Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
{
    CSubNet subNet(netAddr);
    Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
}

void BanMan::Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
{
    CBanEntry banEntry(GetTime());
    banEntry.banReason = banReason;
    if (bantimeoffset <= 0) {
        bantimeoffset = m_default_ban_time;
        sinceUnixEpoch = false;
    }
    banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime()) + bantimeoffset;

    {
        LOCK(m_cs_banned);
        if (m_banned[subNet].nBanUntil < banEntry.nBanUntil) {
            m_banned[subNet] = banEntry;
            m_is_dirty = true;
        } else
            return;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();

    //store banlist to disk immediately if user requested ban
    if (banReason == BanReasonManuallyAdded) DumpBanlist();
}

bool BanMan::Unban(const CNetAddr& netAddr)
{
    CSubNet subNet(netAddr);
    return Unban(subNet);
}

bool BanMan::Unban(const CSubNet& subNet)
{
    {
        LOCK(m_cs_banned);
        if (m_banned.erase(subNet) == 0) return false;
        m_is_dirty = true;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();
    DumpBanlist(); //store banlist to disk immediately
    return true;
}

void BanMan::GetBanned(banmap_t& banMap)
{
    LOCK(m_cs_banned);
    // Sweep the banlist so expired bans are not returned
    SweepBanned();
    banMap = m_banned; //create a thread safe copy
}

void BanMan::SetBanned(const banmap_t& banMap)
{
    LOCK(m_cs_banned);
    m_banned = banMap;
    m_is_dirty = true;
}

void BanMan::SweepBanned()
{
    int64_t now = GetTime();
    bool notifyUI = false;
    {
        LOCK(m_cs_banned);
        banmap_t::iterator it = m_banned.begin();
        while (it != m_banned.end()) {
            CSubNet subNet = (*it).first;
            CBanEntry banEntry = (*it).second;
            if (now > banEntry.nBanUntil) {
                m_banned.erase(it++);
                m_is_dirty = true;
                notifyUI = true;
                LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
            } else
                ++it;
        }
    }
    // update UI
    if (notifyUI && m_client_interface) {
        m_client_interface->BannedListChanged();
    }
}

bool BanMan::BannedSetIsDirty()
{
    LOCK(m_cs_banned);
    return m_is_dirty;
}

void BanMan::SetBannedSetDirty(bool dirty)
{
    LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
    m_is_dirty = dirty;
}
<commit_msg>Bitcoin: 1ffa4ce27d4ea6c1067d8984455df97994c7713e (banman: reformulate nBanUtil calculation).<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <banman.h>

#include <netaddress.h>
#include <ui_interface.h>
#include <util/system.h>
#include <util/time.h>

BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
    : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
{
    if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist..."));

    int64_t nStart = GetTimeMillis();
    m_is_dirty = false;
    banmap_t banmap;
    if (m_ban_db.Read(banmap)) {
        SetBanned(banmap);        // thread save setter
        SetBannedSetDirty(false); // no need to write down, just read data
        SweepBanned();            // sweep out unused entries

        LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat  %dms\n",
            banmap.size(), GetTimeMillis() - nStart);
    } else {
        LogPrintf("Invalid or missing banlist.dat; recreating\n");
        SetBannedSetDirty(true); // force write
        DumpBanlist();
    }
}

BanMan::~BanMan()
{
    DumpBanlist();
}

void BanMan::DumpBanlist()
{
    SweepBanned(); // clean unused entries (if bantime has expired)

    if (!BannedSetIsDirty()) return;

    int64_t nStart = GetTimeMillis();

    banmap_t banmap;
    GetBanned(banmap);
    if (m_ban_db.Write(banmap)) {
        SetBannedSetDirty(false);
    }

    LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat  %dms\n",
        banmap.size(), GetTimeMillis() - nStart);
}

void BanMan::ClearBanned()
{
    {
        LOCK(m_cs_banned);
        m_banned.clear();
        m_is_dirty = true;
    }
    DumpBanlist(); //store banlist to disk
    if (m_client_interface) m_client_interface->BannedListChanged();
}

bool BanMan::IsBanned(CNetAddr netAddr)
{
    LOCK(m_cs_banned);
    for (const auto& it : m_banned) {
        CSubNet subNet = it.first;
        CBanEntry banEntry = it.second;

        if (subNet.Match(netAddr) && GetTime() < banEntry.nBanUntil) {
            return true;
        }
    }
    return false;
}

bool BanMan::IsBanned(CSubNet subNet)
{
    LOCK(m_cs_banned);
    banmap_t::iterator i = m_banned.find(subNet);
    if (i != m_banned.end()) {
        CBanEntry banEntry = (*i).second;
        if (GetTime() < banEntry.nBanUntil) {
            return true;
        }
    }
    return false;
}

void BanMan::Ban(const CNetAddr& netAddr, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
{
    CSubNet subNet(netAddr);
    Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
}

void BanMan::Ban(const CSubNet& subNet, const BanReason& banReason, int64_t bantimeoffset, bool sinceUnixEpoch)
{
    CBanEntry banEntry(GetTime());
    banEntry.banReason = banReason;

    int64_t normalized_bantimeoffset = bantimeoffset;
    bool normalized_sinceUnixEpoch = sinceUnixEpoch;
    if (bantimeoffset <= 0) {
        normalized_bantimeoffset = m_default_ban_time;
        normalized_sinceUnixEpoch = false;
    }
    banEntry.nBanUntil = (normalized_sinceUnixEpoch ? 0 : GetTime()) + normalized_bantimeoffset;

    {
        LOCK(m_cs_banned);
        if (m_banned[subNet].nBanUntil < banEntry.nBanUntil) {
            m_banned[subNet] = banEntry;
            m_is_dirty = true;
        } else
            return;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();

    //store banlist to disk immediately if user requested ban
    if (banReason == BanReasonManuallyAdded) DumpBanlist();
}

bool BanMan::Unban(const CNetAddr& netAddr)
{
    CSubNet subNet(netAddr);
    return Unban(subNet);
}

bool BanMan::Unban(const CSubNet& subNet)
{
    {
        LOCK(m_cs_banned);
        if (m_banned.erase(subNet) == 0) return false;
        m_is_dirty = true;
    }
    if (m_client_interface) m_client_interface->BannedListChanged();
    DumpBanlist(); //store banlist to disk immediately
    return true;
}

void BanMan::GetBanned(banmap_t& banMap)
{
    LOCK(m_cs_banned);
    // Sweep the banlist so expired bans are not returned
    SweepBanned();
    banMap = m_banned; //create a thread safe copy
}

void BanMan::SetBanned(const banmap_t& banMap)
{
    LOCK(m_cs_banned);
    m_banned = banMap;
    m_is_dirty = true;
}

void BanMan::SweepBanned()
{
    int64_t now = GetTime();
    bool notifyUI = false;
    {
        LOCK(m_cs_banned);
        banmap_t::iterator it = m_banned.begin();
        while (it != m_banned.end()) {
            CSubNet subNet = (*it).first;
            CBanEntry banEntry = (*it).second;
            if (now > banEntry.nBanUntil) {
                m_banned.erase(it++);
                m_is_dirty = true;
                notifyUI = true;
                LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
            } else
                ++it;
        }
    }
    // update UI
    if (notifyUI && m_client_interface) {
        m_client_interface->BannedListChanged();
    }
}

bool BanMan::BannedSetIsDirty()
{
    LOCK(m_cs_banned);
    return m_is_dirty;
}

void BanMan::SetBannedSetDirty(bool dirty)
{
    LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
    m_is_dirty = dirty;
}
<|endoftext|>