<commit_before>/*
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// @author Andrei Alexandrescu (andrei.alexandrescu@fb.com)

#include "Benchmark.h"
#include "Foreach.h"
#include "json.h"
#include "String.h"

#include <algorithm>
#include <boost/regex.hpp>
#include <cmath>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>

using namespace std;

DEFINE_bool(benchmark, false, "Run benchmarks.");
DEFINE_bool(json, false, "Output in JSON format.");

DEFINE_string(bm_regex, "",
              "Only benchmarks whose names match this regex will be run.");

DEFINE_int64(bm_min_usec, 100,
             "Minimum # of microseconds we'll accept for each benchmark.");

DEFINE_int64(bm_min_iters, 1,
             "Minimum # of iterations we'll try for each benchmark.");

DEFINE_int32(bm_max_secs, 1,
             "Maximum # of seconds we'll spend on each benchmark.");

namespace folly {

BenchmarkSuspender::NanosecondsSpent BenchmarkSuspender::nsSpent;

typedef function<uint64_t(unsigned int)> BenchmarkFun;
static vector<tuple<const char*, const char*, BenchmarkFun>> benchmarks;

// Add the global baseline
BENCHMARK(globalBenchmarkBaseline) {
  asm volatile("");
}

void detail::addBenchmarkImpl(const char* file, const char* name,
                              BenchmarkFun fun) {
  benchmarks.emplace_back(file, name, std::move(fun));
}

/**
 * Given a point, gives density at that point as a number 0.0 < x <=
 * 1.0. The result is 1.0 if all samples are equal to where, and
 * decreases near 0 if all points are far away from it. The density is
 * computed with the help of a radial basis function.
 */
static double density(const double * begin, const double *const end,
                      const double where, const double bandwidth) {
  assert(begin < end);
  assert(bandwidth > 0.0);
  double sum = 0.0;
  FOR_EACH_RANGE (i, begin, end) {
    auto d = (*i - where) / bandwidth;
    sum += exp(- d * d);
  }
  return sum / (end - begin);
}

/**
 * Computes mean and variance for a bunch of data points. Note that
 * mean is currently not being used.
 */
static pair<double, double>
meanVariance(const double * begin, const double *const end) {
  assert(begin < end);
  double sum = 0.0, sum2 = 0.0;
  FOR_EACH_RANGE (i, begin, end) {
    sum += *i;
    sum2 += *i * *i;
  }
  auto const n = end - begin;
  return make_pair(sum / n, sqrt((sum2 - sum * sum / n) / n));
}

/**
 * Computes the mode of a sample set through brute force. Assumes
 * input is sorted.
 */
static double mode(const double * begin, const double *const end) {
  assert(begin < end);
  // Lower bound and upper bound for result and their respective
  // densities.
  auto
    result = 0.0,
    bestDensity = 0.0;

  // Get the variance so we pass it down to density()
  auto const sigma = meanVariance(begin, end).second;
  if (!sigma) {
    // No variance means constant signal
    return *begin;
  }

  FOR_EACH_RANGE (i, begin, end) {
    assert(i == begin || *i >= i[-1]);
    auto candidate = density(begin, end, *i, sigma * sqrt(2.0));
    if (candidate > bestDensity) {
      // Found a new best
      bestDensity = candidate;
      result = *i;
    } else {
      // Density is decreasing... we could break here if we definitely
      // knew this is unimodal.
    }
  }

  return result;
}

/**
 * Given a bunch of benchmark samples, estimate the actual run time.
 */
static double estimateTime(double * begin, double * end) {
  assert(begin < end);

  // Current state of the art: get the minimum. After some
  // experimentation, it seems taking the minimum is the best.

  return *min_element(begin, end);

  // What follows after estimates the time as the mode of the
  // distribution.

  // Select the awesomest (i.e. most frequent) result. We do this by
  // sorting and then computing the longest run length.
  sort(begin, end);

  // Eliminate outliers. A time much larger than the minimum time is
  // considered an outlier.
  while (end[-1] > 2.0 * *begin) {
    --end;
    if (begin == end) {
      LOG(INFO) << *begin;
    }
    assert(begin < end);
  }

  double result = 0;

  /* Code used just for comparison purposes */ {
    unsigned bestFrequency = 0;
    unsigned candidateFrequency = 1;
    double candidateValue = *begin;
    for (auto current = begin + 1; ; ++current) {
      if (current == end || *current != candidateValue) {
        // Done with the current run, see if it was best
        if (candidateFrequency > bestFrequency) {
          bestFrequency = candidateFrequency;
          result = candidateValue;
        }
        if (current == end) {
          break;
        }
        // Start a new run
        candidateValue = *current;
        candidateFrequency = 1;
      } else {
        // Cool, inside a run, increase the frequency
        ++candidateFrequency;
      }
    }
  }

  result = mode(begin, end);

  return result;
}

static double runBenchmarkGetNSPerIteration(const BenchmarkFun& fun,
                                            const double globalBaseline) {
  // They key here is accuracy; too low numbers means the accuracy was
  // coarse. We up the ante until we get to at least minNanoseconds
  // timings.
  static uint64_t resolutionInNs = 0, coarseResolutionInNs = 0;
  if (!resolutionInNs) {
    timespec ts;
    CHECK_EQ(0, clock_getres(detail::DEFAULT_CLOCK_ID, &ts));
    CHECK_EQ(0, ts.tv_sec) << "Clock sucks.";
    CHECK_LT(0, ts.tv_nsec) << "Clock too fast for its own good.";
    CHECK_EQ(1, ts.tv_nsec) << "Clock too coarse, upgrade your kernel.";
    resolutionInNs = ts.tv_nsec;
  }
  // We choose a minimum minimum (sic) of 100,000 nanoseconds, but if
  // the clock resolution is worse than that, it will be larger. In
  // essence we're aiming at making the quantization noise 0.01%.
  static const auto minNanoseconds =
    max(FLAGS_bm_min_usec * 1000UL,
        min(resolutionInNs * 100000, 1000000000ULL));

  // We do measurements in several epochs and take the minimum, to
  // account for jitter.
  static const unsigned int epochs = 1000;
  // We establish a total time budget as we don't want a measurement
  // to take too long. This will curtail the number of actual epochs.
  const uint64_t timeBudgetInNs = FLAGS_bm_max_secs * 1000000000;
  timespec global;
  CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &global));

  double epochResults[epochs] = { 0 };
  size_t actualEpochs = 0;

  for (; actualEpochs < epochs; ++actualEpochs) {
    for (unsigned int n = FLAGS_bm_min_iters; n < (1UL << 30); n *= 2) {
      auto const nsecs = fun(n);
      if (nsecs < minNanoseconds) {
        continue;
      }
      // We got an accurate enough timing, done. But only save if
      // smaller than the current result.
      epochResults[actualEpochs] = max(0.0, double(nsecs) / n - globalBaseline);
      // Done with the current epoch, we got a meaningful timing.
      break;
    }
    timespec now;
    CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &now));
    if (detail::timespecDiff(now, global) >= timeBudgetInNs) {
      // No more time budget available.
      ++actualEpochs;
      break;
    }
  }

  // If the benchmark was basically drowned in baseline noise, it's
  // possible it became negative.
  return max(0.0, estimateTime(epochResults, epochResults + actualEpochs));
}

struct ScaleInfo {
  double boundary;
  const char* suffix;
};

static const ScaleInfo kTimeSuffixes[] {
  { 365.25 * 24 * 3600, "years" },
  { 24 * 3600, "days" },
  { 3600, "hr" },
  { 60, "min" },
  { 1, "s" },
  { 1E-3, "ms" },
  { 1E-6, "us" },
  { 1E-9, "ns" },
  { 1E-12, "ps" },
  { 1E-15, "fs" },
  { 0, NULL },
};

static const ScaleInfo kMetricSuffixes[] {
  { 1E24, "Y" },  // yotta
  { 1E21, "Z" },  // zetta
  { 1E18, "X" },  // "exa" written with suffix 'X' so as to not create
                  //   confusion with scientific notation
  { 1E15, "P" },  // peta
  { 1E12, "T" },  // terra
  { 1E9, "G" },   // giga
  { 1E6, "M" },   // mega
  { 1E3, "K" },   // kilo
  { 1, "" },
  { 1E-3, "m" },  // milli
  { 1E-6, "u" },  // micro
  { 1E-9, "n" },  // nano
  { 1E-12, "p" }, // pico
  { 1E-15, "f" }, // femto
  { 1E-18, "a" }, // atto
  { 1E-21, "z" }, // zepto
  { 1E-24, "y" }, // yocto
  { 0, NULL },
};

static string humanReadable(double n, unsigned int decimals,
                            const ScaleInfo* scales) {
  if (std::isinf(n) || std::isnan(n)) {
    return folly::to<string>(n);
  }

  const double absValue = fabs(n);
  const ScaleInfo* scale = scales;
  while (absValue < scale[0].boundary && scale[1].suffix != NULL) {
    ++scale;
  }

  const double scaledValue = n / scale->boundary;
  return stringPrintf("%.*f%s", decimals, scaledValue, scale->suffix);
}

static string readableTime(double n, unsigned int decimals) {
  return humanReadable(n, decimals, kTimeSuffixes);
}

static string metricReadable(double n, unsigned int decimals) {
  return humanReadable(n, decimals, kMetricSuffixes);
}

static void printBenchmarkResultsAsTable(
  const vector<tuple<const char*, const char*, double> >& data) {
  // Width available
  static const uint columns = 76;

  // Compute the longest benchmark name
  size_t longestName = 0;
  FOR_EACH_RANGE (i, 1, benchmarks.size()) {
    longestName = max(longestName, strlen(get<1>(benchmarks[i])));
  }

  // Print a horizontal rule
  auto separator = [&](char pad) {
    puts(string(columns, pad).c_str());
  };

  // Print header for a file
  auto header = [&](const char* file) {
    separator('=');
    printf("%-*srelative  time/iter  iters/s\n",
           columns - 28, file);
    separator('=');
  };

  double baselineNsPerIter = numeric_limits<double>::max();
  const char* lastFile = "";

  for (auto& datum : data) {
    auto file = get<0>(datum);
    if (strcmp(file, lastFile)) {
      // New file starting
      header(file);
      lastFile = file;
    }

    string s = get<1>(datum);
    if (s == "-") {
      separator('-');
      continue;
    }
    bool useBaseline /* = void */;
    if (s[0] == '%') {
      s.erase(0, 1);
      useBaseline = true;
    } else {
      baselineNsPerIter = get<2>(datum);
      useBaseline = false;
    }
    s.resize(columns - 29, ' ');
    auto nsPerIter = get<2>(datum);
    auto secPerIter = nsPerIter / 1E9;
    auto itersPerSec = 1 / secPerIter;
    if (!useBaseline) {
      // Print without baseline
      printf("%*s           %9s  %7s\n",
             static_cast<int>(s.size()), s.c_str(),
             readableTime(secPerIter, 2).c_str(),
             metricReadable(itersPerSec, 2).c_str());
    } else {
      // Print with baseline
      auto rel = baselineNsPerIter / nsPerIter * 100.0;
      printf("%*s %7.2f%%  %9s  %7s\n",
             static_cast<int>(s.size()), s.c_str(),
             rel,
             readableTime(secPerIter, 2).c_str(),
             metricReadable(itersPerSec, 2).c_str());
    }
  }
  separator('=');
}

static void printBenchmarkResultsAsJson(
  const vector<tuple<const char*, const char*, double> >& data) {
  dynamic d = dynamic::object;
  for (auto& datum: data) {
    d[std::get<1>(datum)] = std::get<2>(datum) * 1000.;
  }

  printf("%s\n", toPrettyJson(d).c_str());
}

static void printBenchmarkResults(
  const vector<tuple<const char*, const char*, double> >& data) {

  if (FLAGS_json) {
    printBenchmarkResultsAsJson(data);
  } else {
    printBenchmarkResultsAsTable(data);
  }
}

void runBenchmarks() {
  CHECK(!benchmarks.empty());

  vector<tuple<const char*, const char*, double>> results;
  results.reserve(benchmarks.size() - 1);

  std::unique_ptr<boost::regex> bmRegex;
  if (!FLAGS_bm_regex.empty()) {
    bmRegex.reset(new boost::regex(FLAGS_bm_regex));
  }

  // PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS.

  auto const globalBaseline = runBenchmarkGetNSPerIteration(
    get<2>(benchmarks.front()), 0);
  FOR_EACH_RANGE (i, 1, benchmarks.size()) {
    double elapsed = 0.0;
    if (!strcmp(get<1>(benchmarks[i]), "-") == 0) { // skip separators
      if (bmRegex && !boost::regex_search(get<1>(benchmarks[i]), *bmRegex)) {
        continue;
      }
      elapsed = runBenchmarkGetNSPerIteration(get<2>(benchmarks[i]),
                                              globalBaseline);
    }
    results.emplace_back(get<0>(benchmarks[i]),
                         get<1>(benchmarks[i]), elapsed);
  }

  // PLEASE MAKE NOISE. MEASUREMENTS DONE.

  printBenchmarkResults(results);
}

} // namespace folly
<commit_msg>revert folly/Benchmark.cpp<commit_after>/*
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// @author Andrei Alexandrescu (andrei.alexandrescu@fb.com)

#include "Benchmark.h"
#include "Foreach.h"
#include "json.h"
#include "String.h"

#include <algorithm>
#include <boost/regex.hpp>
#include <cmath>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>

using namespace std;

DEFINE_bool(benchmark, false, "Run benchmarks.");
DEFINE_bool(json, false, "Output in JSON format.");

DEFINE_string(bm_regex, "",
              "Only benchmarks whose names match this regex will be run.");

DEFINE_int64(bm_min_usec, 100,
             "Minimum # of microseconds we'll accept for each benchmark.");

DEFINE_int64(bm_min_iters, 1,
             "Minimum # of iterations we'll try for each benchmark.");

DEFINE_int32(bm_max_secs, 1,
             "Maximum # of seconds we'll spend on each benchmark.");

namespace folly {

BenchmarkSuspender::NanosecondsSpent BenchmarkSuspender::nsSpent;

typedef function<uint64_t(unsigned int)> BenchmarkFun;
static vector<tuple<const char*, const char*, BenchmarkFun>> benchmarks;

// Add the global baseline
BENCHMARK(globalBenchmarkBaseline) {
  asm volatile("");
}

void detail::addBenchmarkImpl(const char* file, const char* name,
                              BenchmarkFun fun) {
  benchmarks.emplace_back(file, name, std::move(fun));
}

/**
 * Given a point, gives density at that point as a number 0.0 < x <=
 * 1.0. The result is 1.0 if all samples are equal to where, and
 * decreases near 0 if all points are far away from it. The density is
 * computed with the help of a radial basis function.
 */
static double density(const double * begin, const double *const end,
                      const double where, const double bandwidth) {
  assert(begin < end);
  assert(bandwidth > 0.0);
  double sum = 0.0;
  FOR_EACH_RANGE (i, begin, end) {
    auto d = (*i - where) / bandwidth;
    sum += exp(- d * d);
  }
  return sum / (end - begin);
}

/**
 * Computes mean and variance for a bunch of data points. Note that
 * mean is currently not being used.
 */
static pair<double, double>
meanVariance(const double * begin, const double *const end) {
  assert(begin < end);
  double sum = 0.0, sum2 = 0.0;
  FOR_EACH_RANGE (i, begin, end) {
    sum += *i;
    sum2 += *i * *i;
  }
  auto const n = end - begin;
  return make_pair(sum / n, sqrt((sum2 - sum * sum / n) / n));
}

/**
 * Computes the mode of a sample set through brute force. Assumes
 * input is sorted.
 */
static double mode(const double * begin, const double *const end) {
  assert(begin < end);
  // Lower bound and upper bound for result and their respective
  // densities.
  auto
    result = 0.0,
    bestDensity = 0.0;

  // Get the variance so we pass it down to density()
  auto const sigma = meanVariance(begin, end).second;
  if (!sigma) {
    // No variance means constant signal
    return *begin;
  }

  FOR_EACH_RANGE (i, begin, end) {
    assert(i == begin || *i >= i[-1]);
    auto candidate = density(begin, end, *i, sigma * sqrt(2.0));
    if (candidate > bestDensity) {
      // Found a new best
      bestDensity = candidate;
      result = *i;
    } else {
      // Density is decreasing... we could break here if we definitely
      // knew this is unimodal.
    }
  }

  return result;
}

/**
 * Given a bunch of benchmark samples, estimate the actual run time.
 */
static double estimateTime(double * begin, double * end) {
  assert(begin < end);

  // Current state of the art: get the minimum. After some
  // experimentation, it seems taking the minimum is the best.

  return *min_element(begin, end);

  // What follows after estimates the time as the mode of the
  // distribution.

  // Select the awesomest (i.e. most frequent) result. We do this by
  // sorting and then computing the longest run length.
  sort(begin, end);

  // Eliminate outliers. A time much larger than the minimum time is
  // considered an outlier.
  while (end[-1] > 2.0 * *begin) {
    --end;
    if (begin == end) {
      LOG(INFO) << *begin;
    }
    assert(begin < end);
  }

  double result = 0;

  /* Code used just for comparison purposes */ {
    unsigned bestFrequency = 0;
    unsigned candidateFrequency = 1;
    double candidateValue = *begin;
    for (auto current = begin + 1; ; ++current) {
      if (current == end || *current != candidateValue) {
        // Done with the current run, see if it was best
        if (candidateFrequency > bestFrequency) {
          bestFrequency = candidateFrequency;
          result = candidateValue;
        }
        if (current == end) {
          break;
        }
        // Start a new run
        candidateValue = *current;
        candidateFrequency = 1;
      } else {
        // Cool, inside a run, increase the frequency
        ++candidateFrequency;
      }
    }
  }

  result = mode(begin, end);

  return result;
}

static double runBenchmarkGetNSPerIteration(const BenchmarkFun& fun,
                                            const double globalBaseline) {
  // They key here is accuracy; too low numbers means the accuracy was
  // coarse. We up the ante until we get to at least minNanoseconds
  // timings.
  static uint64_t resolutionInNs = 0, coarseResolutionInNs = 0;
  if (!resolutionInNs) {
    timespec ts;
    CHECK_EQ(0, clock_getres(detail::DEFAULT_CLOCK_ID, &ts));
    CHECK_EQ(0, ts.tv_sec) << "Clock sucks.";
    CHECK_LT(0, ts.tv_nsec) << "Clock too fast for its own good.";
    CHECK_EQ(1, ts.tv_nsec) << "Clock too coarse, upgrade your kernel.";
    resolutionInNs = ts.tv_nsec;
  }
  // We choose a minimum minimum (sic) of 100,000 nanoseconds, but if
  // the clock resolution is worse than that, it will be larger. In
  // essence we're aiming at making the quantization noise 0.01%.
  static const auto minNanoseconds =
    max(FLAGS_bm_min_usec * 1000UL, min(resolutionInNs * 100000, 1000000000UL));

  // We do measurements in several epochs and take the minimum, to
  // account for jitter.
  static const unsigned int epochs = 1000;
  // We establish a total time budget as we don't want a measurement
  // to take too long. This will curtail the number of actual epochs.
  const uint64_t timeBudgetInNs = FLAGS_bm_max_secs * 1000000000;
  timespec global;
  CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &global));

  double epochResults[epochs] = { 0 };
  size_t actualEpochs = 0;

  for (; actualEpochs < epochs; ++actualEpochs) {
    for (unsigned int n = FLAGS_bm_min_iters; n < (1UL << 30); n *= 2) {
      auto const nsecs = fun(n);
      if (nsecs < minNanoseconds) {
        continue;
      }
      // We got an accurate enough timing, done. But only save if
      // smaller than the current result.
      epochResults[actualEpochs] = max(0.0, double(nsecs) / n - globalBaseline);
      // Done with the current epoch, we got a meaningful timing.
      break;
    }
    timespec now;
    CHECK_EQ(0, clock_gettime(CLOCK_REALTIME, &now));
    if (detail::timespecDiff(now, global) >= timeBudgetInNs) {
      // No more time budget available.
      ++actualEpochs;
      break;
    }
  }

  // If the benchmark was basically drowned in baseline noise, it's
  // possible it became negative.
  return max(0.0, estimateTime(epochResults, epochResults + actualEpochs));
}

struct ScaleInfo {
  double boundary;
  const char* suffix;
};

static const ScaleInfo kTimeSuffixes[] {
  { 365.25 * 24 * 3600, "years" },
  { 24 * 3600, "days" },
  { 3600, "hr" },
  { 60, "min" },
  { 1, "s" },
  { 1E-3, "ms" },
  { 1E-6, "us" },
  { 1E-9, "ns" },
  { 1E-12, "ps" },
  { 1E-15, "fs" },
  { 0, NULL },
};

static const ScaleInfo kMetricSuffixes[] {
  { 1E24, "Y" },  // yotta
  { 1E21, "Z" },  // zetta
  { 1E18, "X" },  // "exa" written with suffix 'X' so as to not create
                  //   confusion with scientific notation
  { 1E15, "P" },  // peta
  { 1E12, "T" },  // terra
  { 1E9, "G" },   // giga
  { 1E6, "M" },   // mega
  { 1E3, "K" },   // kilo
  { 1, "" },
  { 1E-3, "m" },  // milli
  { 1E-6, "u" },  // micro
  { 1E-9, "n" },  // nano
  { 1E-12, "p" }, // pico
  { 1E-15, "f" }, // femto
  { 1E-18, "a" }, // atto
  { 1E-21, "z" }, // zepto
  { 1E-24, "y" }, // yocto
  { 0, NULL },
};

static string humanReadable(double n, unsigned int decimals,
                            const ScaleInfo* scales) {
  if (std::isinf(n) || std::isnan(n)) {
    return folly::to<string>(n);
  }

  const double absValue = fabs(n);
  const ScaleInfo* scale = scales;
  while (absValue < scale[0].boundary && scale[1].suffix != NULL) {
    ++scale;
  }

  const double scaledValue = n / scale->boundary;
  return stringPrintf("%.*f%s", decimals, scaledValue, scale->suffix);
}

static string readableTime(double n, unsigned int decimals) {
  return humanReadable(n, decimals, kTimeSuffixes);
}

static string metricReadable(double n, unsigned int decimals) {
  return humanReadable(n, decimals, kMetricSuffixes);
}

static void printBenchmarkResultsAsTable(
  const vector<tuple<const char*, const char*, double> >& data) {
  // Width available
  static const uint columns = 76;

  // Compute the longest benchmark name
  size_t longestName = 0;
  FOR_EACH_RANGE (i, 1, benchmarks.size()) {
    longestName = max(longestName, strlen(get<1>(benchmarks[i])));
  }

  // Print a horizontal rule
  auto separator = [&](char pad) {
    puts(string(columns, pad).c_str());
  };

  // Print header for a file
  auto header = [&](const char* file) {
    separator('=');
    printf("%-*srelative  time/iter  iters/s\n",
           columns - 28, file);
    separator('=');
  };

  double baselineNsPerIter = numeric_limits<double>::max();
  const char* lastFile = "";

  for (auto& datum : data) {
    auto file = get<0>(datum);
    if (strcmp(file, lastFile)) {
      // New file starting
      header(file);
      lastFile = file;
    }

    string s = get<1>(datum);
    if (s == "-") {
      separator('-');
      continue;
    }
    bool useBaseline /* = void */;
    if (s[0] == '%') {
      s.erase(0, 1);
      useBaseline = true;
    } else {
      baselineNsPerIter = get<2>(datum);
      useBaseline = false;
    }
    s.resize(columns - 29, ' ');
    auto nsPerIter = get<2>(datum);
    auto secPerIter = nsPerIter / 1E9;
    auto itersPerSec = 1 / secPerIter;
    if (!useBaseline) {
      // Print without baseline
      printf("%*s           %9s  %7s\n",
             static_cast<int>(s.size()), s.c_str(),
             readableTime(secPerIter, 2).c_str(),
             metricReadable(itersPerSec, 2).c_str());
    } else {
      // Print with baseline
      auto rel = baselineNsPerIter / nsPerIter * 100.0;
      printf("%*s %7.2f%%  %9s  %7s\n",
             static_cast<int>(s.size()), s.c_str(),
             rel,
             readableTime(secPerIter, 2).c_str(),
             metricReadable(itersPerSec, 2).c_str());
    }
  }
  separator('=');
}

static void printBenchmarkResultsAsJson(
  const vector<tuple<const char*, const char*, double> >& data) {
  dynamic d = dynamic::object;
  for (auto& datum: data) {
    d[std::get<1>(datum)] = std::get<2>(datum) * 1000.;
  }

  printf("%s\n", toPrettyJson(d).c_str());
}

static void printBenchmarkResults(
  const vector<tuple<const char*, const char*, double> >& data) {

  if (FLAGS_json) {
    printBenchmarkResultsAsJson(data);
  } else {
    printBenchmarkResultsAsTable(data);
  }
}

void runBenchmarks() {
  CHECK(!benchmarks.empty());

  vector<tuple<const char*, const char*, double>> results;
  results.reserve(benchmarks.size() - 1);

  std::unique_ptr<boost::regex> bmRegex;
  if (!FLAGS_bm_regex.empty()) {
    bmRegex.reset(new boost::regex(FLAGS_bm_regex));
  }

  // PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS.

  auto const globalBaseline = runBenchmarkGetNSPerIteration(
    get<2>(benchmarks.front()), 0);
  FOR_EACH_RANGE (i, 1, benchmarks.size()) {
    double elapsed = 0.0;
    if (!strcmp(get<1>(benchmarks[i]), "-") == 0) { // skip separators
      if (bmRegex && !boost::regex_search(get<1>(benchmarks[i]), *bmRegex)) {
        continue;
      }
      elapsed = runBenchmarkGetNSPerIteration(get<2>(benchmarks[i]),
                                              globalBaseline);
    }
    results.emplace_back(get<0>(benchmarks[i]),
                         get<1>(benchmarks[i]), elapsed);
  }

  // PLEASE MAKE NOISE. MEASUREMENTS DONE.

  printBenchmarkResults(results);
}

} // namespace folly
<|endoftext|>


<commit_before>#include <sstream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>

#include "entity.h"
#include "board.h"

using namespace std;

Entity::Entity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity) :
	position(position),
	speed(speed),
	deletable(false),
	orientation(0),
	size(size),
	name(name),
	owner(owner),
	board(board),
	sight_radius(sight_radius),
	solid(solid),
	capacity(capacity)
{
	static size_t idCount = 0;
	id = idCount++;
	adjustPosition();
	stringstream message;
	message << "Created Entity " << this
		<< " with ID " << id
		<< " of kind " << name
		<< " owned by board " << &board
		<< " at " << position.x << "," << position.y;
	Logger::getInstance()->writeInformation(message.str());
}

Entity::~Entity() {
	stringstream message;
	message << "Killing Entity " << this << " of kind " << name;
	Logger::getInstance()->writeInformation(message.str());
}

bool Entity::adjustPosition() {
	double topX = board.sizeX - size.x;
	double topY = board.sizeY - size.y;
	r2 oldpos = position;
	position = {clip(position.x, 0, topX),clip(position.y, 0, topY)};
	bool adjusted = oldpos != position;
	if (adjusted) {
		setFrame();
	}
	return adjusted;
}

///////////////////////////////////////////////////////////////////////////////
// HIC SVNT DRACONES
///////////////////////////////////////////////////////////////////////////////

#include <queue>
#include <set>

struct TSNode {
	r2 position;
	double g, f;
	shared_ptr<TSNode> previous;
	TSNode(r2 position, double g, double f, shared_ptr<TSNode> previous) :
		position(position), g(g), f(f), previous(previous) {};
};

class compare {
	public:
		bool operator()(const shared_ptr<TSNode> a, const shared_ptr<TSNode> b) {
			return a->f > b->f;
		}
};

void Entity::addTarget(r2 newTarget) {
	auto round = [](r2 a) {return r2(floor(a.x)+.5, floor(a.y)+.5);};
	r2
		end = targeted() ? waypoints.back() : position,
		start = round(newTarget);

	priority_queue<TSNode, vector<shared_ptr<TSNode>>, compare> open;
	auto h = [&end](r2& p) {return (p - end).length();};
	auto f = [&h](TSNode n) {return h(n.position) + n.g;};
	bool closed[board.sizeX][board.sizeY];
	for(size_t i = 0; i < board.sizeX; i++) {
		for(size_t j = 0; j < board.sizeY; j++) {
			closed[i][j] = false;
		}
	}

	open.emplace(make_shared<TSNode>(start, 0, h(start), nullptr));
	while (open.size() > 0) {
		auto c = open.top();
		open.pop();
		auto cpos = c->position;
		if(closed[(int)floor(cpos.x)][(int)floor(cpos.y)]) {
			continue;
		}
		closed[(int)floor(cpos.x)][(int)floor(cpos.y)] = true;
		if ((int)cpos.x == (int)end.x && (int)cpos.y == (int)end.y) {
			for (auto p = c; p; p = p->previous) {
				auto pos = p->position;
				waypoints.push_back(p->position);
			}
			return;
		}
		for(auto y = cpos.y - 1; y <= cpos.y + 1; y++) {
			for(auto x = cpos.x - 1; x <= cpos.x + 1; x++) {
				auto p = round(r2(x, y));
				if ((p == cpos) ||
						!(canEnter(p) &&
							canEnter(rectangle::box(p - size/2, cpos - size/2, size)))) {
					continue;
				}
				auto n = make_shared<TSNode>(p, (cpos - p).length() + c->g, .0, c);
				n->f = f(*n);
				if (closed[(int)floor(p.x)][(int)floor(p.y)]) {
					continue;
				}
				while(n->previous?
						n->previous->previous?
						canEnter(rectangle::box(p, n->previous->previous->position, size))
						:false
						:false) {
					n->previous = n->previous->previous;
				}
				open.emplace(n);
			}
		}
	}
}

void Entity::unsetTarget() {
	waypoints.clear();
}

r2 Entity::target() {
	return waypoints.size() > 0?
		waypoints.front():
		r2(0, 0);
}

bool Entity::targeted() {
	return waypoints.size() > 0;
}

void Entity::collide(Entity* other) {
	if(other) {
		if(!deletable &&
				!other->deletable) {
			other->collide(*this);
		}
	}
}

void Entity::collide(Entity& other) {}

void Entity::collide(ResourceEntity& other) {}

bool Entity::canEnter(rectangle r) {
	auto& p = r.position;
	auto& s = r.size;
	for (int dx = 0; dx < s.x + 1; dx++) {
		for (int dy = 0; dy < s.y + 1; dy++) {
			auto t = board.getTerrain(floor(p.x + dx), floor(p.y + dy));
			if (t) {
				if(t->solid) {
					return false;
				}
			}
		}
	}
	auto colliders = board.selectEntities([this, r](shared_ptr<Entity> e) {
			return (*e != *this) &&
			e->solid &&
			!e->deletable &&
			(rectangle(e->position, e->size).intersects(r));
			});
	return colliders.size() == 0;
}

bool Entity::canEnter(r2 newPosition) {
	auto newCenter = newPosition + size / 2;
	if (newCenter.x < 0 ||
			newCenter.y < 0 ||
			newCenter.x >= board.sizeX ||
			newCenter.y >= board.sizeY) {
		return false;
	}
	return canEnter(rectangle(newPosition, size));
}

void Entity::update() {
	if (targeted()) {
		auto traj = trajectory();
		orientation = atan2(traj.y, traj.x);
		auto dr = speed*board.dt/1000;
		if (pow(dr, 2) < sqDistance()) {
			auto newPos = position + r2::fromPolar(orientation, dr);
			rectangle shapeCandidate(newPos, size);
			auto colliders = board.selectEntities([this, shapeCandidate](shared_ptr<Entity> e) {
					return (*e != *this) &&
					(rectangle(e->position, e->size).intersects(shapeCandidate));
					});
			for(auto c : colliders) {
				collide(c.get());
			}
			if (!canEnter(newPos)) {
				unsetTarget();
				return;
			}
			position = newPos;
		} else {
			position = target() - size/2;
			waypoints.pop_front();
		}
		if (adjustPosition()) {
			unsetTarget();
		}
		setFrame();
	}
}

r2 Entity::center() {
	return position + (size/2);
}

r2 Entity::getPosition() {
	return position;
}

r2 Entity::trajectory() {
	return target() - center();
}

double Entity::sqDistance() {
	return trajectory().sqLength();
}

double Entity::distance() {
	return trajectory().length();
}

Directions Entity::getDirection(){
	return static_cast<Directions>((unsigned)floor(4*orientation/M_PI+.5)%8);
}

void Entity::setDeletable() {
	deletable = true;
	setFrame();
}

bool Entity::getDeletable() {
	return deletable;
}

size_t Entity::getId() {
	return id;
}

void Entity::setFrame() {
	frame = board.getFrame();
}

size_t Entity::getFrame() {
	return frame;
}

bool Entity::operator==(Entity& other) {
	return this == &other;
}

bool Entity::operator!=(Entity& other) {
	return !operator==(other);
}

string Entity::serialize() {
	stringstream ret;
	ret << "E\t" << id << '\t' << name << '\t'
		<< frame << '\t'
		<< owner.getId() << '\t'
		<< position.x << '\t' << position.y << '\t'
		<< orientation << endl;
	return ret.str();
}

ResourceEntity::ResourceEntity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity):Entity(name, board, owner, position, size, speed, sight_radius, solid, capacity)
{}

void ResourceEntity::collide(Entity& other) {
	if(!getDeletable() &&
			!other.getDeletable()) {
		stringstream message;
		message << "Un " << other.name << " de " << other.owner.name << " encontró" << name;
		if(other.owner.grantResources(name, capacity)) {
			setDeletable();
			message << "; ahora " << other.owner.name
				<< " tiene " << other.owner.getResources()[name]
				<< " " << name;
		} else {
			message << "; pero no puede tomarlos";
		}
		Logger::getInstance()->writeInformation(message.str());
	}
}

void ResourceEntity::collide(ResourceEntity& other) {}

<commit_msg>Redondeo<commit_after>#include <sstream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>

#include "entity.h"
#include "board.h"

using namespace std;

Entity::Entity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity) :
	position(position),
	speed(speed),
	deletable(false),
	orientation(0),
	size(size),
	name(name),
	owner(owner),
	board(board),
	sight_radius(sight_radius),
	solid(solid),
	capacity(capacity)
{
	static size_t idCount = 0;
	id = idCount++;
	adjustPosition();
	stringstream message;
	message << "Created Entity " << this
		<< " with ID " << id
		<< " of kind " << name
		<< " owned by board " << &board
		<< " at " << position.x << "," << position.y;
	Logger::getInstance()->writeInformation(message.str());
}

Entity::~Entity() {
	stringstream message;
	message << "Killing Entity " << this << " of kind " << name;
	Logger::getInstance()->writeInformation(message.str());
}

bool Entity::adjustPosition() {
	double topX = board.sizeX - size.x;
	double topY = board.sizeY - size.y;
	r2 oldpos = position;
	position = {clip(position.x, 0, topX),clip(position.y, 0, topY)};
	bool adjusted = oldpos != position;
	if (adjusted) {
		setFrame();
	}
	return adjusted;
}

///////////////////////////////////////////////////////////////////////////////
// HIC SVNT DRACONES
///////////////////////////////////////////////////////////////////////////////

#include <queue>
#include <set>

struct TSNode {
	r2 position;
	double g, f;
	shared_ptr<TSNode> previous;
	TSNode(r2 position, double g, double f, shared_ptr<TSNode> previous) :
		position(position), g(g), f(f), previous(previous) {};
};

class compare {
	public:
		bool operator()(const shared_ptr<TSNode> a, const shared_ptr<TSNode> b) {
			return a->f > b->f;
		}
};

void Entity::addTarget(r2 newTarget) {
	auto round = [](r2 a) {return r2(floor(a.x)+.5, floor(a.y)+.5);};
	r2
		end = round(targeted() ? waypoints.back() : position),
		start = round(newTarget);

	priority_queue<TSNode, vector<shared_ptr<TSNode>>, compare> open;
	auto h = [&end](r2& p) {return (p - end).length();};
	auto f = [&h](TSNode n) {return h(n.position) + n.g;};
	bool closed[board.sizeX][board.sizeY];
	for(size_t i = 0; i < board.sizeX; i++) {
		for(size_t j = 0; j < board.sizeY; j++) {
			closed[i][j] = false;
		}
	}

	open.emplace(make_shared<TSNode>(start, 0, h(start), nullptr));
	while (open.size() > 0) {
		auto c = open.top();
		open.pop();
		auto cpos = c->position;
		if(closed[(int)floor(cpos.x)][(int)floor(cpos.y)]) {
			continue;
		}
		closed[(int)floor(cpos.x)][(int)floor(cpos.y)] = true;
		if ((int)cpos.x == (int)end.x && (int)cpos.y == (int)end.y) {
			for (auto p = c; p; p = p->previous) {
				auto pos = p->position;
				waypoints.push_back(p->position);
			}
			return;
		}
		for(auto y = cpos.y - 1; y <= cpos.y + 1; y++) {
			for(auto x = cpos.x - 1; x <= cpos.x + 1; x++) {
				auto p = r2(x, y);
				if ((p == cpos) ||
						!(canEnter(p) &&
							canEnter(rectangle::box(p - size/2, cpos - size/2, size)))) {
					continue;
				}
				auto n = make_shared<TSNode>(p, (cpos - p).length() + c->g, .0, c);
				n->f = f(*n);
				if (closed[(int)floor(p.x)][(int)floor(p.y)]) {
					continue;
				}
				while(n->previous?
						n->previous->previous?
						canEnter(rectangle::box(p, n->previous->previous->position, size))
						:false
						:false) {
					n->previous = n->previous->previous;
				}
				open.emplace(n);
			}
		}
	}
}

void Entity::unsetTarget() {
	waypoints.clear();
}

r2 Entity::target() {
	return waypoints.size() > 0?
		waypoints.front():
		r2(0, 0);
}

bool Entity::targeted() {
	return waypoints.size() > 0;
}

void Entity::collide(Entity* other) {
	if(other) {
		if(!deletable &&
				!other->deletable) {
			other->collide(*this);
		}
	}
}

void Entity::collide(Entity& other) {}

void Entity::collide(ResourceEntity& other) {}

bool Entity::canEnter(rectangle r) {
	auto& p = r.position;
	auto& s = r.size;
	for (int dx = 0; dx < s.x + 1; dx++) {
		for (int dy = 0; dy < s.y + 1; dy++) {
			auto t = board.getTerrain(floor(p.x + dx), floor(p.y + dy));
			if (t) {
				if(t->solid) {
					return false;
				}
			}
		}
	}
	auto colliders = board.selectEntities([this, r](shared_ptr<Entity> e) {
			return (*e != *this) &&
			e->solid &&
			!e->deletable &&
			(rectangle(e->position, e->size).intersects(r));
			});
	return colliders.size() == 0;
}

bool Entity::canEnter(r2 newPosition) {
	auto newCenter = newPosition + size / 2;
	if (newCenter.x < 0 ||
			newCenter.y < 0 ||
			newCenter.x >= board.sizeX ||
			newCenter.y >= board.sizeY) {
		return false;
	}
	return canEnter(rectangle(newPosition, size));
}

void Entity::update() {
	if (targeted()) {
		auto traj = trajectory();
		orientation = atan2(traj.y, traj.x);
		auto dr = speed*board.dt/1000;
		if (pow(dr, 2) < sqDistance()) {
			auto newPos = position + r2::fromPolar(orientation, dr);
			rectangle shapeCandidate(newPos, size);
			auto colliders = board.selectEntities([this, shapeCandidate](shared_ptr<Entity> e) {
					return (*e != *this) &&
					(rectangle(e->position, e->size).intersects(shapeCandidate));
					});
			for(auto c : colliders) {
				collide(c.get());
			}
			if (!canEnter(newPos)) {
				unsetTarget();
				return;
			}
			position = newPos;
		} else {
			position = target() - size/2;
			waypoints.pop_front();
		}
		if (adjustPosition()) {
			unsetTarget();
		}
		setFrame();
	}
}

r2 Entity::center() {
	return position + (size/2);
}

r2 Entity::getPosition() {
	return position;
}

r2 Entity::trajectory() {
	return target() - center();
}

double Entity::sqDistance() {
	return trajectory().sqLength();
}

double Entity::distance() {
	return trajectory().length();
}

Directions Entity::getDirection(){
	return static_cast<Directions>((unsigned)floor(4*orientation/M_PI+.5)%8);
}

void Entity::setDeletable() {
	deletable = true;
	setFrame();
}

bool Entity::getDeletable() {
	return deletable;
}

size_t Entity::getId() {
	return id;
}

void Entity::setFrame() {
	frame = board.getFrame();
}

size_t Entity::getFrame() {
	return frame;
}

bool Entity::operator==(Entity& other) {
	return this == &other;
}

bool Entity::operator!=(Entity& other) {
	return !operator==(other);
}

string Entity::serialize() {
	stringstream ret;
	ret << "E\t" << id << '\t' << name << '\t'
		<< frame << '\t'
		<< owner.getId() << '\t'
		<< position.x << '\t' << position.y << '\t'
		<< orientation << endl;
	return ret.str();
}

ResourceEntity::ResourceEntity(std::string name, ABoard& board, Player& owner, r2 position, r2 size, double speed, int sight_radius, bool solid, int capacity):Entity(name, board, owner, position, size, speed, sight_radius, solid, capacity)
{}

void ResourceEntity::collide(Entity& other) {
	if(!getDeletable() &&
			!other.getDeletable()) {
		stringstream message;
		message << "Un " << other.name << " de " << other.owner.name << " encontró" << name;
		if(other.owner.grantResources(name, capacity)) {
			setDeletable();
			message << "; ahora " << other.owner.name
				<< " tiene " << other.owner.getResources()[name]
				<< " " << name;
		} else {
			message << "; pero no puede tomarlos";
		}
		Logger::getInstance()->writeInformation(message.str());
	}
}

void ResourceEntity::collide(ResourceEntity& other) {}

<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
    Random Number Generator interface
*/

#include <nta/types/Types.hpp>
#include <cstdlib>
#include <string>
#include <vector>

#ifndef NTA_RANDOM_HPP
#define NTA_RANDOM_HPP

typedef NTA_UInt64 (*RandomSeedFuncPtr)();

namespace nta {
  /**
   * @b Responsibility
   * Provides standardized random number generation for the NuPIC Runtime Engine.
   * Seed can be logged in one run and then set in another.
   * @b Rationale
   * Makes it possible to reproduce tests that are driven by random number generation.
   *
   * @b Description
   * Functionality is similar to the standard random() function that is provided by C.
   *
   * Each Random object is a random number generator. There are three ways of
   * creating one:
   * 1) explicit seed
   *       Random rng(seed);
   * 2) self-seeded
   *       Random rng;
   * 3) named generator -- normally self-seeded, but seed may be
   *    set explicitly through an environment variable
   *       Random rng("level2TP");
   *    If NTA_RANDOM_DEBUG is set, this object will log its self-seed
   *    The seed can be explicitly set through NTA_RANDOM_SEED_level2TP
   *
   * Good self-seeds are generated by an internal global random number generator.
   * This global rng is seeded from the current time, but its seed may be
   * overridden with NTA_RANDOM_SEED
   *
   * Automated tests that use random numbers should normally use named generators.
   * This allows them to get a different seed each time, but also allows reproducibility
   * in the case that a test failure is triggered by a particular seed.
   *
   * Random should not be used if cryptographic strength is required (e.g. for
   * generating a challenge in an authentication scheme).
   *
   * @todo Add ability to specify different rng algorithms.
   */
  class RandomImpl;

  class Random
  {
  public:
    /**
     * Retrieve the seeder. If seeder not set, allocates the
     * singleton and and initializes the seeder.
     */
    static RandomSeedFuncPtr getSeeder();

    Random(UInt64 seed = 0);

    // support copy constructor and operator= -- these require non-default
    // implementations because of the impl_ pointer.
    // They do a deep copy of impl_ so that an RNG and its copy generate the
    // same set of numbers.
    Random(const Random&);
    Random& operator=(const Random&);
    ~Random();

    // return a value uniformly distributed between 0 and max-1
    UInt32 getUInt32(UInt32 max = MAX32);
    UInt64 getUInt64(UInt64 max = MAX64);
    // return a double uniformly distributed on 0...1.0
    Real64 getReal64();

    // populate choices with a random selection of num elements from population
    // templated functions must be defined in header
    template <typename T>
    void sample(T population[], UInt32 nPopulation,
                T sample[], UInt32 nSample)
    {
      if (nSample == 0)
      {
        return;
      }
      UInt32 nextChoice = 0;
      for (UInt32 i = 0; i < nPopulation; ++i)
      {
        if (getUInt32(nPopulation - i) < (nSample - nextChoice))
        {
          sample[nextChoice] = population[i];
          ++nextChoice;
          if (nextChoice == nSample)
          {
            break;
          }
        }
      }
    }

    // randomly shuffle the elements
    template <class RandomAccessIterator>
    void shuffle(RandomAccessIterator first, RandomAccessIterator last)
    {
      std::random_shuffle(first, last, *this);
    }

    // for STL compatibility
    UInt32 operator()(UInt32 n = MAX32) { return getUInt32(n); }

    // normally used for debugging only
    UInt64 getSeed() {return seed_;}

    // for STL
    typedef UInt32 argument_type;
    typedef UInt32 result_type;

    result_type max() { return MAX32; }
    result_type min() { return 0; }

    static const UInt32 MAX32;
    static const UInt64 MAX64;

    // called by the plugin framework so that plugins
    // get the "global" seeder
    static void initSeeder(const RandomSeedFuncPtr r);

    static void shutdown();

  protected:

    // each "universe" (application/plugin/python module) has its own instance,
    // but the instance should be NULL in all but one
    static Random *theInstanceP_;
    // seeder_ is a function called by the constructor to get new random seeds
    // If not set when we call Random constructor, then the singleton is allocated
    // and seeder_ is set to a function that uses our singleton
    // initFromPlatformServices can also be used to initialize the seeder_
    static RandomSeedFuncPtr seeder_;

    void reseed(UInt64 seed);

    RandomImpl *impl_;
    UInt64 seed_;

    friend class RandomTest;
    friend std::ostream& operator<<(std::ostream&, const Random&);
    friend std::istream& operator>>(std::istream&, Random&);
    friend NTA_UInt64 GetRandomSeed();

  };

  // serialization/deserialization
  std::ostream& operator<<(std::ostream&, const Random&);
  std::istream& operator>>(std::istream&, Random&);

  // This function returns seeds from the Random singleton in our
  // "universe" (application, plugin, python module). If, when the
  // Random constructor is called, seeder_ is NULL, then seeder_ is
  // set to this function. The plugin framework can override this
  // behavior by explicitly setting the seeder to the RandomSeeder
  // function provided by the application.
  NTA_UInt64 GetRandomSeed();

} // namespace nta

#endif // NTA_RANDOM_HPP

<commit_msg>Add missing include.<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
    Random Number Generator interface
*/

#include <nta/types/Types.hpp>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>

#ifndef NTA_RANDOM_HPP
#define NTA_RANDOM_HPP

typedef NTA_UInt64 (*RandomSeedFuncPtr)();

namespace nta {
  /**
   * @b Responsibility
   * Provides standardized random number generation for the NuPIC Runtime Engine.
   * Seed can be logged in one run and then set in another.
   * @b Rationale
   * Makes it possible to reproduce tests that are driven by random number generation.
   *
   * @b Description
   * Functionality is similar to the standard random() function that is provided by C.
   *
   * Each Random object is a random number generator. There are three ways of
   * creating one:
   * 1) explicit seed
   *       Random rng(seed);
   * 2) self-seeded
   *       Random rng;
   * 3) named generator -- normally self-seeded, but seed may be
   *    set explicitly through an environment variable
   *       Random rng("level2TP");
   *    If NTA_RANDOM_DEBUG is set, this object will log its self-seed
   *    The seed can be explicitly set through NTA_RANDOM_SEED_level2TP
   *
   * Good self-seeds are generated by an internal global random number generator.
   * This global rng is seeded from the current time, but its seed may be
   * overridden with NTA_RANDOM_SEED
   *
   * Automated tests that use random numbers should normally use named generators.
   * This allows them to get a different seed each time, but also allows reproducibility
   * in the case that a test failure is triggered by a particular seed.
   *
   * Random should not be used if cryptographic strength is required (e.g. for
   * generating a challenge in an authentication scheme).
   *
   * @todo Add ability to specify different rng algorithms.
   */
  class RandomImpl;

  class Random
  {
  public:
    /**
     * Retrieve the seeder. If seeder not set, allocates the
     * singleton and and initializes the seeder.
     */
    static RandomSeedFuncPtr getSeeder();

    Random(UInt64 seed = 0);

    // support copy constructor and operator= -- these require non-default
    // implementations because of the impl_ pointer.
    // They do a deep copy of impl_ so that an RNG and its copy generate the
    // same set of numbers.
    Random(const Random&);
    Random& operator=(const Random&);
    ~Random();

    // return a value uniformly distributed between 0 and max-1
    UInt32 getUInt32(UInt32 max = MAX32);
    UInt64 getUInt64(UInt64 max = MAX64);
    // return a double uniformly distributed on 0...1.0
    Real64 getReal64();

    // populate choices with a random selection of num elements from population
    // templated functions must be defined in header
    template <typename T>
    void sample(T population[], UInt32 nPopulation,
                T sample[], UInt32 nSample)
    {
      if (nSample == 0)
      {
        return;
      }
      UInt32 nextChoice = 0;
      for (UInt32 i = 0; i < nPopulation; ++i)
      {
        if (getUInt32(nPopulation - i) < (nSample - nextChoice))
        {
          sample[nextChoice] = population[i];
          ++nextChoice;
          if (nextChoice == nSample)
          {
            break;
          }
        }
      }
    }

    // randomly shuffle the elements
    template <class RandomAccessIterator>
    void shuffle(RandomAccessIterator first, RandomAccessIterator last)
    {
      std::random_shuffle(first, last, *this);
    }

    // for STL compatibility
    UInt32 operator()(UInt32 n = MAX32) { return getUInt32(n); }

    // normally used for debugging only
    UInt64 getSeed() {return seed_;}

    // for STL
    typedef UInt32 argument_type;
    typedef UInt32 result_type;

    result_type max() { return MAX32; }
    result_type min() { return 0; }

    static const UInt32 MAX32;
    static const UInt64 MAX64;

    // called by the plugin framework so that plugins
    // get the "global" seeder
    static void initSeeder(const RandomSeedFuncPtr r);

    static void shutdown();

  protected:

    // each "universe" (application/plugin/python module) has its own instance,
    // but the instance should be NULL in all but one
    static Random *theInstanceP_;
    // seeder_ is a function called by the constructor to get new random seeds
    // If not set when we call Random constructor, then the singleton is allocated
    // and seeder_ is set to a function that uses our singleton
    // initFromPlatformServices can also be used to initialize the seeder_
    static RandomSeedFuncPtr seeder_;

    void reseed(UInt64 seed);

    RandomImpl *impl_;
    UInt64 seed_;

    friend class RandomTest;
    friend std::ostream& operator<<(std::ostream&, const Random&);
    friend std::istream& operator>>(std::istream&, Random&);
    friend NTA_UInt64 GetRandomSeed();

  };

  // serialization/deserialization
  std::ostream& operator<<(std::ostream&, const Random&);
  std::istream& operator>>(std::istream&, Random&);

  // This function returns seeds from the Random singleton in our
  // "universe" (application, plugin, python module). If, when the
  // Random constructor is called, seeder_ is NULL, then seeder_ is
  // set to this function. The plugin framework can override this
  // behavior by explicitly setting the seeder to the RandomSeeder
  // function provided by the application.
  NTA_UInt64 GetRandomSeed();

} // namespace nta

#endif // NTA_RANDOM_HPP

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "text-channel-watcher-proxy-model.h"

#include <TelepathyQt/TextChannel>
#include <TelepathyQt/ChannelClassSpecList>
#include <TelepathyQt/MethodInvocationContext>
#include <TelepathyQt/Types>
#include <TelepathyQt/ReceivedMessage>

#include <KTp/types.h>
#include <KTp/contact.h>
#include <KTp/message.h>

inline Tp::ChannelClassSpecList channelClasses() {
    return Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::textChat();
}

class ChannelWatcher : public QObject, public Tp::RefCounted
{
    Q_OBJECT
public:
    ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent=0);
    int unreadMessageCount() const;
    QString lastMessage() const;
    KTp::Message::MessageDirection lastMessageDirection() const;
    QPersistentModelIndex modelIndex() const;
Q_SIGNALS:
    void messagesChanged();
    void invalidated();
private Q_SLOTS:
    void onMessageReceived(const Tp::ReceivedMessage &message);
    void onMessageSent(const Tp::Message &message);
private:
    QPersistentModelIndex m_index;
    Tp::TextChannelPtr m_channel;
    QString m_lastMessage;
    KTp::Message::MessageDirection m_lastMessageDirection;
};

typedef Tp::SharedPtr<ChannelWatcher> ChannelWatcherPtr;

ChannelWatcher::ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent):
    QObject(parent),
    m_index(index),
    m_channel(channel),
    m_lastMessageDirection(KTp::Message::LocalToRemote)
{
    connect(channel.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), SIGNAL(messagesChanged()));
    connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));

    connect(channel.data(), SIGNAL(messageReceived(Tp::ReceivedMessage)), SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), SLOT(onMessageSent(Tp::Message)));

    //trigger an update to the contact straight away
    QTimer::singleShot(0, this, SIGNAL(messagesChanged()));
}

QPersistentModelIndex ChannelWatcher::modelIndex() const
{
    return m_index;
}

int ChannelWatcher::unreadMessageCount() const
{
    return m_channel->messageQueue().size();
}

QString ChannelWatcher::lastMessage() const
{
    return m_lastMessage;
}

KTp::Message::MessageDirection ChannelWatcher::lastMessageDirection() const
{
    return m_lastMessageDirection;
}

void ChannelWatcher::onMessageReceived(const Tp::ReceivedMessage &message)
{
    if (!message.isDeliveryReport()) {
        m_lastMessage = message.text();
        m_lastMessageDirection = KTp::Message::RemoteToLocal;
        Q_EMIT messagesChanged();
    }
}

void ChannelWatcher::onMessageSent(const Tp::Message &message)
{
    m_lastMessage = message.text();
    m_lastMessageDirection = KTp::Message::LocalToRemote;
    Q_EMIT messagesChanged();
}

namespace KTp {

class TextChannelWatcherProxyModel::Private {
public:
    QHash<KTp::ContactPtr, ChannelWatcherPtr> currentChannels;
};

} //namespace

KTp::TextChannelWatcherProxyModel::TextChannelWatcherProxyModel(QObject *parent) :
    QIdentityProxyModel(parent),
    Tp::AbstractClientObserver(channelClasses(), true),
    d(new TextChannelWatcherProxyModel::Private)
{
}

KTp::TextChannelWatcherProxyModel::~TextChannelWatcherProxyModel()
{
    delete d;
}

void KTp::TextChannelWatcherProxyModel::observeChannels(const Tp::MethodInvocationContextPtr<> &context, const Tp::AccountPtr &account, const Tp::ConnectionPtr &connection, const QList<Tp::ChannelPtr> &channels, const Tp::ChannelDispatchOperationPtr &dispatchOperation, const QList<Tp::ChannelRequestPtr> &requestsSatisfied, const Tp::AbstractClientObserver::ObserverInfo &observerInfo)
{
    Q_UNUSED(context)
    Q_UNUSED(account)
    Q_UNUSED(connection)
    Q_UNUSED(dispatchOperation)
    Q_UNUSED(requestsSatisfied)
    Q_UNUSED(observerInfo)

    if (!sourceModel()) {
        return;
    }

    Q_FOREACH(const Tp::ChannelPtr & channel, channels) {
        Tp::TextChannelPtr textChannel = Tp::TextChannelPtr::dynamicCast(channel);
        if (textChannel) {
            KTp::ContactPtr targetContact = KTp::ContactPtr::qObjectCast(textChannel->targetContact());

            //skip group chats and situations where we don't have a single contact to mark messages for
            if (targetContact.isNull()) {
                continue;
            }

            //if it's not in our source model, ignore the channel
            QModelIndexList matchedContacts = sourceModel()->match(QModelIndex(sourceModel()->index(0,0)), KTp::ContactRole, QVariant::fromValue(targetContact));
            if (matchedContacts.size() !=1) {
                continue;
            }

            QPersistentModelIndex contactIndex(matchedContacts[0]);

            ChannelWatcherPtr watcher = ChannelWatcherPtr(new ChannelWatcher(contactIndex, textChannel));
            d->currentChannels[targetContact] = watcher;

            connect(watcher.data(), SIGNAL(messagesChanged()), SLOT(onChannelMessagesChanged()));
        }
    }
}

QVariant KTp::TextChannelWatcherProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
    const QModelIndex sourceIndex = mapToSource(proxyIndex);
    if (role == KTp::ContactHasTextChannelRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return true;
            }
        }
        return false;
    }

    if (role == KTp::ContactUnreadMessageCountRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->unreadMessageCount();
            }
        }
        return 0;
    }
    if (role == KTp::ContactLastMessageRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessage();
            }
        }
        return QString();
    }
    if (role == KTp::ContactLastMessageDirectionRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessageDirection();
            }
        }
        return KTp::Message::LocalToRemote;
    }

    return sourceIndex.data(role);
}

void KTp::TextChannelWatcherProxyModel::onChannelMessagesChanged()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    dataChanged(index, index);
}

void KTp::TextChannelWatcherProxyModel::onChannelInvalidated()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    const KTp::ContactPtr &contact = index.data(KTp::ContactRole).value<KTp::ContactPtr>();

    d->currentChannels.remove(contact);
    dataChanged(index, index);
}

#include "text-channel-watcher-proxy-model.moc"
#include "moc_text-channel-watcher-proxy-model.cpp"
<commit_msg>Match contacts in watcher proxy by contact id instead of ContactPtr<commit_after>/*
 * Copyright (C) 2013 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "text-channel-watcher-proxy-model.h"

#include <TelepathyQt/TextChannel>
#include <TelepathyQt/ChannelClassSpecList>
#include <TelepathyQt/MethodInvocationContext>
#include <TelepathyQt/Types>
#include <TelepathyQt/ReceivedMessage>

#include <KTp/types.h>
#include <KTp/contact.h>
#include <KTp/message.h>

inline Tp::ChannelClassSpecList channelClasses() {
    return Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::textChat();
}

class ChannelWatcher : public QObject, public Tp::RefCounted
{
    Q_OBJECT
public:
    ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent=0);
    int unreadMessageCount() const;
    QString lastMessage() const;
    KTp::Message::MessageDirection lastMessageDirection() const;
    QPersistentModelIndex modelIndex() const;
Q_SIGNALS:
    void messagesChanged();
    void invalidated();
private Q_SLOTS:
    void onMessageReceived(const Tp::ReceivedMessage &message);
    void onMessageSent(const Tp::Message &message);
private:
    QPersistentModelIndex m_index;
    Tp::TextChannelPtr m_channel;
    QString m_lastMessage;
    KTp::Message::MessageDirection m_lastMessageDirection;
};

typedef Tp::SharedPtr<ChannelWatcher> ChannelWatcherPtr;

ChannelWatcher::ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent):
    QObject(parent),
    m_index(index),
    m_channel(channel),
    m_lastMessageDirection(KTp::Message::LocalToRemote)
{
    connect(channel.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), SIGNAL(messagesChanged()));
    connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));

    connect(channel.data(), SIGNAL(messageReceived(Tp::ReceivedMessage)), SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), SLOT(onMessageSent(Tp::Message)));

    //trigger an update to the contact straight away
    QTimer::singleShot(0, this, SIGNAL(messagesChanged()));
}

QPersistentModelIndex ChannelWatcher::modelIndex() const
{
    return m_index;
}

int ChannelWatcher::unreadMessageCount() const
{
    return m_channel->messageQueue().size();
}

QString ChannelWatcher::lastMessage() const
{
    return m_lastMessage;
}

KTp::Message::MessageDirection ChannelWatcher::lastMessageDirection() const
{
    return m_lastMessageDirection;
}

void ChannelWatcher::onMessageReceived(const Tp::ReceivedMessage &message)
{
    if (!message.isDeliveryReport()) {
        m_lastMessage = message.text();
        m_lastMessageDirection = KTp::Message::RemoteToLocal;
        Q_EMIT messagesChanged();
    }
}

void ChannelWatcher::onMessageSent(const Tp::Message &message)
{
    m_lastMessage = message.text();
    m_lastMessageDirection = KTp::Message::LocalToRemote;
    Q_EMIT messagesChanged();
}

namespace KTp {

class TextChannelWatcherProxyModel::Private {
public:
    QHash<KTp::ContactPtr, ChannelWatcherPtr> currentChannels;
};

} //namespace

KTp::TextChannelWatcherProxyModel::TextChannelWatcherProxyModel(QObject *parent) :
    QIdentityProxyModel(parent),
    Tp::AbstractClientObserver(channelClasses(), true),
    d(new TextChannelWatcherProxyModel::Private)
{
}

KTp::TextChannelWatcherProxyModel::~TextChannelWatcherProxyModel()
{
    delete d;
}

void KTp::TextChannelWatcherProxyModel::observeChannels(const Tp::MethodInvocationContextPtr<> &context, const Tp::AccountPtr &account, const Tp::ConnectionPtr &connection, const QList<Tp::ChannelPtr> &channels, const Tp::ChannelDispatchOperationPtr &dispatchOperation, const QList<Tp::ChannelRequestPtr> &requestsSatisfied, const Tp::AbstractClientObserver::ObserverInfo &observerInfo)
{
    Q_UNUSED(context)
    Q_UNUSED(account)
    Q_UNUSED(connection)
    Q_UNUSED(dispatchOperation)
    Q_UNUSED(requestsSatisfied)
    Q_UNUSED(observerInfo)

    if (!sourceModel()) {
        return;
    }

    Q_FOREACH(const Tp::ChannelPtr & channel, channels) {
        Tp::TextChannelPtr textChannel = Tp::TextChannelPtr::dynamicCast(channel);
        if (textChannel) {
            KTp::ContactPtr targetContact = KTp::ContactPtr::qObjectCast(textChannel->targetContact());

            //skip group chats and situations where we don't have a single contact to mark messages for
            if (targetContact.isNull()) {
                continue;
            }

            //if it's not in our source model, ignore the channel
            QModelIndexList matchedContacts = sourceModel()->match(QModelIndex(sourceModel()->index(0,0)), KTp::IdRole, QVariant::fromValue(targetContact->id()));
            if (matchedContacts.size() !=1) {
                continue;
            }

            QPersistentModelIndex contactIndex(matchedContacts[0]);

            ChannelWatcherPtr watcher = ChannelWatcherPtr(new ChannelWatcher(contactIndex, textChannel));
            d->currentChannels[targetContact] = watcher;

            connect(watcher.data(), SIGNAL(messagesChanged()), SLOT(onChannelMessagesChanged()));
        }
    }
}

QVariant KTp::TextChannelWatcherProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
    const QModelIndex sourceIndex = mapToSource(proxyIndex);
    if (role == KTp::ContactHasTextChannelRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return true;
            }
        }
        return false;
    }

    if (role == KTp::ContactUnreadMessageCountRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->unreadMessageCount();
            }
        }
        return 0;
    }
    if (role == KTp::ContactLastMessageRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessage();
            }
        }
        return QString();
    }
    if (role == KTp::ContactLastMessageDirectionRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessageDirection();
            }
        }
        return KTp::Message::LocalToRemote;
    }

    return sourceIndex.data(role);
}

void KTp::TextChannelWatcherProxyModel::onChannelMessagesChanged()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    dataChanged(index, index);
}

void KTp::TextChannelWatcherProxyModel::onChannelInvalidated()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    const KTp::ContactPtr &contact = index.data(KTp::ContactRole).value<KTp::ContactPtr>();

    d->currentChannels.remove(contact);
    dataChanged(index, index);
}

#include "text-channel-watcher-proxy-model.moc"
#include "moc_text-channel-watcher-proxy-model.cpp"
<|endoftext|>


<commit_before>#include "regex.h"

#include <iostream>
#include <algorithm>

#include "document.h"
#include "prolog.h"
#include "pi.h"
#include "doctype.h"
#include "attribute.h"
#include "element.h"
#include "composite_element.h"
#include "content.h"

static std::string schema_to_regex(CompositeElement *);
static std::string element_to_regex(Element *);
static std::string simple_element_to_regex(Element *);
static std::string complexe_type_to_regex(CompositeElement *);
static std::string choice_to_regex(CompositeElement *);
static std::string sequence_to_regex(CompositeElement *);
static std::string string_to_regex();
static std::string date_to_regex();
static std::string mixed_to_regex();

std::string xsl_to_regex(Document * doc)
{
  CompositeElement * root = dynamic_cast<CompositeElement *>(doc->root());
  if (root == nullptr)
    return "^$";
  if (root->begin_tag() == "xsd:schema")
    return "^" + schema_to_regex(root) + "$";
  return "^$";
}

std::string schema_to_regex(CompositeElement * s)
{
  std::string r;
  for (auto c : s->content())
  {
    auto e = dynamic_cast<Element *>(c);
    if (e != nullptr && e->name() == "xsd:element")
      r += element_to_regex(e);
  }
  return r;
}

std::string element_to_regex(Element * e)
{
  auto it_name = std::find_if(e->attributes().begin(), e->attributes().end(),
      [](Attribute * a) { return a->name() == "name"; });
  if (it_name == e->attributes().end())
    return "";

  auto name = (*it_name)->value();

  auto ce = dynamic_cast<CompositeElement *>(e);
  if (ce != nullptr)
  {
    CompositeElement * cce = nullptr;
    if (ce->content().size() >= 1
        && (cce = dynamic_cast<CompositeElement *>(ce->content().front())) != nullptr
        && cce->begin_tag() == "xsd:complexType")
    {
      return "<" + name + ">" + complexe_type_to_regex(cce) + "</" + name + ">";
    }
  }
  else
  {
    return "<" + name + ">" + simple_element_to_regex(e) + "</" + name + ">";
  }
  return "";
}

std::string simple_element_to_regex(Element * e)
{
  auto it_type = std::find_if(e->attributes().begin(), e->attributes().end(),
      [](Attribute * a) { return a->name() == "type"; });
  if (it_type == e->attributes().end())
    return "";

  auto type = (*it_type)->value();
  if (type == "xsd:string")
    return string_to_regex();
  else if (type == "xsd:date")
    return date_to_regex();
  return "";
}

std::string complexe_type_to_regex(CompositeElement * e)
{
  if (e->content().size() < 1)
    return "";

  CompositeElement * ce = dynamic_cast<CompositeElement *>(e->content().front());
  if (ce == nullptr)
    return "";

  std::string s;
  if (ce->begin_tag() == "xsd:choice")
  {
    s += choice_to_regex(ce);
  }
  else if (ce->begin_tag() == "xsd:sequence")
  {
    s += sequence_to_regex(ce);
  }
  return s;
}

std::string choice_to_regex(CompositeElement * e)
{
  std::string s;
  for (auto c : e->content())
  {
    auto ce = dynamic_cast<Element *>(c);
    if (ce)
    {
      s += element_to_regex(ce);
      if (c != e->content().back())
        s += "|";
    }
  }
  return "(" + s + ")";
}

std::string sequence_to_regex(CompositeElement * e)
{
  std::string s;
  for (auto c : e->content())
  {
    auto ce = dynamic_cast<Element *>(c);
    if (ce)
    {
      s += "(" + element_to_regex(ce) + ")";
    }
  }
  return "(" + s + ")";
}

std::string string_to_regex()
{
  return "[^<]*";
}

std::string date_to_regex()
{
  return "[0-9]{4}-[0-9]{2}-[0-9]{2}(((\\+|-)[0-2][0-9]:[0-5][0-9])|Z)?";
}

std::string mixed_to_regex()
{
  return "[^<]*";
}
<commit_msg>Ajout de blancs possible entres les balises<commit_after>#include "regex.h"

#include <iostream>
#include <algorithm>

#include "document.h"
#include "prolog.h"
#include "pi.h"
#include "doctype.h"
#include "attribute.h"
#include "element.h"
#include "composite_element.h"
#include "content.h"

static std::string schema_to_regex(CompositeElement *);
static std::string element_to_regex(Element *);
static std::string simple_element_to_regex(Element *);
static std::string complexe_type_to_regex(CompositeElement *);
static std::string choice_to_regex(CompositeElement *);
static std::string sequence_to_regex(CompositeElement *);
static std::string string_to_regex();
static std::string date_to_regex();
static std::string mixed_to_regex();
static std::string blank_to_regex();

std::string xsl_to_regex(Document * doc)
{
  CompositeElement * root = dynamic_cast<CompositeElement *>(doc->root());
  if (root == nullptr)
    return "^$";
  if (root->begin_tag() == "xsd:schema")
    return "^" + schema_to_regex(root) + "$";
  return "^$";
}

std::string schema_to_regex(CompositeElement * s)
{
  std::string r;
  for (auto c : s->content())
  {
    auto e = dynamic_cast<Element *>(c);
    if (e != nullptr && e->name() == "xsd:element")
      r += element_to_regex(e);
  }
  return r;
}

std::string element_to_regex(Element * e)
{
  auto it_name = std::find_if(e->attributes().begin(), e->attributes().end(),
      [](Attribute * a) { return a->name() == "name"; });
  if (it_name == e->attributes().end())
    return "";

  auto name = (*it_name)->value();

  auto ce = dynamic_cast<CompositeElement *>(e);
  if (ce != nullptr)
  {
    CompositeElement * cce = nullptr;
    if (ce->content().size() >= 1
        && (cce = dynamic_cast<CompositeElement *>(ce->content().front())) != nullptr
        && cce->begin_tag() == "xsd:complexType")
    {
      return "<" + name + ">\\s?" + complexe_type_to_regex(cce) + "</" + name + ">\\s?";
    }
  }
  else
  {
    return "<" + name + "\\s?>" + simple_element_to_regex(e) + "</" + name + "\\s?>";
  }
  return "";
}

std::string simple_element_to_regex(Element * e)
{
  auto it_type = std::find_if(e->attributes().begin(), e->attributes().end(),
      [](Attribute * a) { return a->name() == "type"; });
  if (it_type == e->attributes().end())
    return "";

  auto type = (*it_type)->value();
  if (type == "xsd:string")
    return string_to_regex();
  else if (type == "xsd:date")
    return date_to_regex();
  return "";
}

std::string complexe_type_to_regex(CompositeElement * e)
{
  if (e->content().size() < 1)
    return "";

  CompositeElement * ce = dynamic_cast<CompositeElement *>(e->content().front());
  if (ce == nullptr)
    return "";

  std::string s;
  if (ce->begin_tag() == "xsd:choice")
  {
    s += choice_to_regex(ce);
  }
  else if (ce->begin_tag() == "xsd:sequence")
  {
    s += sequence_to_regex(ce);
  }
  return s;
}

std::string choice_to_regex(CompositeElement * e)
{
  std::string s;
  for (auto c : e->content())
  {
    auto ce = dynamic_cast<Element *>(c);
    if (ce)
    {
      s += element_to_regex(ce);
      if (c != e->content().back())
        s += "|";
    }
  }
  return blank_to_regex() + "(" + s + ")" + blank_to_regex();
}

std::string sequence_to_regex(CompositeElement * e)
{
  std::string s;
  for (auto c : e->content())
  {
    auto ce = dynamic_cast<Element *>(c);
    if (ce)
    {
      s += element_to_regex(ce) + blank_to_regex();
    }
  }
  return blank_to_regex() + s;
}

std::string string_to_regex()
{
  return "[^<]*";
}

std::string date_to_regex()
{
  return "[0-9]{4}-[0-9]{2}-[0-9]{2}(((\\+|-)[0-2][0-9]:[0-5][0-9])|Z)?";
}

std::string mixed_to_regex()
{
  return "[^<]*";
}

std::string blank_to_regex()
{
  return "\\s*";
}
<|endoftext|>