<commit_before>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP
#define METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP

#include "Methcla/Audio/IO/Driver.hpp"
#include "Methcla/Audio/Types.h"
#include "Methcla/Exception.hpp"

#include <AudioUnit/AudioUnit.h>

#include <boost/cstdint.hpp>
#include <boost/exception/all.hpp>

namespace Methcla { namespace Audio { namespace IO
{
    struct OSStatusInfoTag { };
    typedef boost::error_info<OSStatusInfoTag,OSStatus> OSStatusInfo;

    class RemoteIODriver : public Driver
    {
    public:
        RemoteIODriver();
        virtual ~RemoteIODriver();

        virtual double sampleRate() const { return m_sampleRate; }
        virtual size_t numInputs() const { return m_numInputs; }
        virtual size_t numOutputs() const { return m_numOutputs; }
        virtual size_t bufferSize() const { return m_bufferSize; }

        virtual void start();
        virtual void stop();

    private:
        static void InterruptionCallback(void *inClientData, UInt32 inInterruption);
        static OSStatus InputCallback(void                         *inRefCon,
                                      AudioUnitRenderActionFlags   *ioActionFlags,
                                      const AudioTimeStamp         *inTimeStamp,
                                      UInt32                       inBusNumber,
                                      UInt32                       inNumberFrames,
                                      AudioBufferList              *ioData);
        static OSStatus RenderCallback(void                         *inRefCon,
                                       AudioUnitRenderActionFlags   *ioActionFlags,
                                       const AudioTimeStamp         *inTimeStamp,
                                       UInt32                       inBusNumber,
                                       UInt32                       inNumberFrames,
                                       AudioBufferList              *ioData);

    private:
        double              m_sampleRate;
        size_t              m_numInputs;
        size_t              m_numOutputs;
        size_t              m_bufferSize;
        AudioUnit           m_rioUnit;
        sample_t**          m_inputBuffers;
        sample_t**          m_outputBuffers;
    };
}; }; };

#endif // METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP
<commit_msg>Mark overridden Driver methods as overrides<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP
#define METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP

#include "Methcla/Audio/IO/Driver.hpp"
#include "Methcla/Audio/Types.h"
#include "Methcla/Exception.hpp"

#include <AudioUnit/AudioUnit.h>

#include <boost/cstdint.hpp>
#include <boost/exception/all.hpp>

namespace Methcla { namespace Audio { namespace IO
{
    struct OSStatusInfoTag { };
    typedef boost::error_info<OSStatusInfoTag,OSStatus> OSStatusInfo;

    class RemoteIODriver : public Driver
    {
    public:
        RemoteIODriver();
        virtual ~RemoteIODriver();

        virtual double sampleRate() const override { return m_sampleRate; }
        virtual size_t numInputs() const override { return m_numInputs; }
        virtual size_t numOutputs() const override { return m_numOutputs; }
        virtual size_t bufferSize() const override { return m_bufferSize; }

        virtual void start() override;
        virtual void stop() override;

    private:
        static void InterruptionCallback(void *inClientData, UInt32 inInterruption);
        static OSStatus InputCallback(void                         *inRefCon,
                                      AudioUnitRenderActionFlags   *ioActionFlags,
                                      const AudioTimeStamp         *inTimeStamp,
                                      UInt32                       inBusNumber,
                                      UInt32                       inNumberFrames,
                                      AudioBufferList              *ioData);
        static OSStatus RenderCallback(void                         *inRefCon,
                                       AudioUnitRenderActionFlags   *ioActionFlags,
                                       const AudioTimeStamp         *inTimeStamp,
                                       UInt32                       inBusNumber,
                                       UInt32                       inNumberFrames,
                                       AudioBufferList              *ioData);

    private:
        double              m_sampleRate;
        size_t              m_numInputs;
        size_t              m_numOutputs;
        size_t              m_bufferSize;
        AudioUnit           m_rioUnit;
        sample_t**          m_inputBuffers;
        sample_t**          m_outputBuffers;
    };
}; }; };

#endif // METHCLA_AUDIO_IO_REMOTEIODRIVER_HPP
<|endoftext|>


<commit_before>///
/// @file  pi_deleglise_rivat_parallel1.cpp
/// @brief Parallel implementation of the Deleglise-Rivat prime
///        counting algorithm. In the Deleglise-Rivat algorithm there
///        are 3 additional types of special leaves compared to the
///        Lagarias-Miller-Odlyzko algorithm: trivial special leaves,
///        clustered easy leaves and sparse easy leaves.
///
///        This implementation is based on the paper:
///        Tomás Oliveira e Silva, Computing pi(x): the combinatorial
///        method, Revista do DETUA, vol. 4, no. 6, March 2006,
///        pp. 759-768.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "S2.hpp"
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <min_max.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S2LoadBalancer.hpp>
#include <tos_counters.hpp>
#include <S1.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <algorithm>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array.
/// For each element that is unmarked the first time update
/// the special counters tree data structure.
///
template <typename T>
void cross_off(BitSieve& sieve,
               int64_t low,
               int64_t high,
               int64_t prime,
               WheelItem& w,
               T& counters)
{
  int64_t segment_size = sieve.size();
  int64_t k = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; k < high; k += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    if (sieve[k - low])
    {
      sieve.unset(k - low);
      cnt_update(counters, k - low, segment_size);
    }
  }

  w.next_multiple = k;
  w.wheel_index = wheel_index;
}

/// Compute the S2 contribution of the hard special leaves.
/// Each thread processes the interval
/// [low_thread, low_thread + segments * segment_size[
/// and the missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the parent S2_hard() function.
///
int64_t S2_hard_thread(int64_t x,
                        int64_t y,
                        int64_t z,
                        int64_t c,
                        int64_t segment_size,
                        int64_t segments_per_thread,
                        int64_t thread_num,
                        int64_t low,
                        int64_t limit,
                        vector<int32_t>& pi,
                        vector<int32_t>& primes,
                        vector<int32_t>& lpf,
                        vector<int32_t>& mu,
                        vector<int64_t>& mu_sum,
                        vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t max_prime = min3(isqrt(x / low), isqrt(z), y);
  int64_t pi_max = pi[max_prime];
  int64_t S2_thread = 0;

  if (c > pi_max)
    return 0;

  BitSieve sieve(segment_size);
  Wheel wheel(primes, low, pi_max + 1, c);
  vector<int32_t> counters(segment_size);
  phi.resize(pi_max + 1, 0);
  mu_sum.resize(pi_max + 1, 0);

  // segmeted sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve the multiples of the first c primes
    sieve.pre_sieve(c, low);

    // Initialize special tree data structure from sieve
    cnt_finit(sieve, counters, segment_size);

    // For c + 1 <= b <= pi_sqrty
    // Find all special leaves: n = primes[b] * m, with mu[m] != 0 and primes[b] < lpf[m]
    // which satisfy: low <= (x / n) < high
    for (int64_t end = min(pi_sqrty, pi_max); b <= end; b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t n = prime * m;
          int64_t count = cnt_query(counters, (x / n) - low);
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(sieve, low, high, prime, wheel[b], counters);
    }

    // For pi_sqrty <= b <= pi_sqrtz
    // Find all hard special leaves: n = primes[b] * primes[l]
    // which satisfy: low <= (x / n) < high
    for (; b <= pi_max; b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min3(x / (prime * low), z / prime, y)];
      int64_t min_hard_leaf = max3(x / (prime * high), y / prime, prime);

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_hard_leaf; l--)
      {
        int64_t n = prime * primes[l];
        int64_t xn = x / n;
        int64_t count = cnt_query(counters, xn - low);
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(sieve, low, high, prime, wheel[b], counters);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves which require
/// a sieve (in order to reduce the memory usage).
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
///
int64_t S2_hard(int64_t x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 vector<int32_t>& pi,
                 vector<int32_t>& primes,
                 vector<int32_t>& lpf,
                 vector<int32_t>& mu,
                 int threads)
{
  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = z + 1;

  S2LoadBalancer loadBalancer(x, y, z, threads);
  int64_t segment_size = loadBalancer.get_min_segment_size();
  int64_t segments_per_thread = 1;
  vector<int64_t> phi_total(pi[min(isqrt(z), y)] + 1, 0);

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_hard_thread(x, y, z, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);
  }

  return S2_total;
}

/// Calculate the contribution of the special leaves.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t z,
           int64_t c,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  int64_t limit = z + 1;
  threads = validate_threads(threads, limit);
  vector<int32_t> pi = generate_pi(y);

  int64_t s2_trivial = S2_trivial(x, y, z, c, threads);
  int64_t s2_easy = S2_easy(x, y, z, c, threads);
  int64_t s2_hard = S2_hard(x, y, z, c, pi, primes, lpf, mu, threads);
  int64_t s2 = s2_trivial + s2_easy + s2_hard;

  return s2;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat_parallel1(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha(x, 0.0017154, -0.0508992, 0.483613, 0.0672202);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t p2 = P2(x, y, threads);

  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = pi_bsearch(primes, y);
  int64_t c = PhiTiny::get_c(y);
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2 = S2(x, y, z, c, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<commit_msg>Fix erroneous parameter order<commit_after>///
/// @file  pi_deleglise_rivat_parallel1.cpp
/// @brief Parallel implementation of the Deleglise-Rivat prime
///        counting algorithm. In the Deleglise-Rivat algorithm there
///        are 3 additional types of special leaves compared to the
///        Lagarias-Miller-Odlyzko algorithm: trivial special leaves,
///        clustered easy leaves and sparse easy leaves.
///
///        This implementation is based on the paper:
///        Tomás Oliveira e Silva, Computing pi(x): the combinatorial
///        method, Revista do DETUA, vol. 4, no. 6, March 2006,
///        pp. 759-768.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "S2.hpp"
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <min_max.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S2LoadBalancer.hpp>
#include <tos_counters.hpp>
#include <S1.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <algorithm>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array.
/// For each element that is unmarked the first time update
/// the special counters tree data structure.
///
template <typename T>
void cross_off(BitSieve& sieve,
               int64_t low,
               int64_t high,
               int64_t prime,
               WheelItem& w,
               T& counters)
{
  int64_t segment_size = sieve.size();
  int64_t k = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; k < high; k += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    if (sieve[k - low])
    {
      sieve.unset(k - low);
      cnt_update(counters, k - low, segment_size);
    }
  }

  w.next_multiple = k;
  w.wheel_index = wheel_index;
}

/// Compute the S2 contribution of the hard special leaves.
/// Each thread processes the interval
/// [low_thread, low_thread + segments * segment_size[
/// and the missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the parent S2_hard() function.
///
int64_t S2_hard_thread(int64_t x,
                        int64_t y,
                        int64_t z,
                        int64_t c,
                        int64_t segment_size,
                        int64_t segments_per_thread,
                        int64_t thread_num,
                        int64_t low,
                        int64_t limit,
                        vector<int32_t>& pi,
                        vector<int32_t>& primes,
                        vector<int32_t>& lpf,
                        vector<int32_t>& mu,
                        vector<int64_t>& mu_sum,
                        vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t max_prime = min3(isqrt(x / low), isqrt(z), y);
  int64_t pi_max = pi[max_prime];
  int64_t S2_thread = 0;

  if (c > pi_max)
    return 0;

  BitSieve sieve(segment_size);
  Wheel wheel(primes, pi_max + 1, low);
  vector<int32_t> counters(segment_size);
  phi.resize(pi_max + 1, 0);
  mu_sum.resize(pi_max + 1, 0);

  // segmeted sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve the multiples of the first c primes
    sieve.pre_sieve(c, low);

    // Initialize special tree data structure from sieve
    cnt_finit(sieve, counters, segment_size);

    // For c + 1 <= b <= pi_sqrty
    // Find all special leaves: n = primes[b] * m, with mu[m] != 0 and primes[b] < lpf[m]
    // which satisfy: low <= (x / n) < high
    for (int64_t end = min(pi_sqrty, pi_max); b <= end; b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t n = prime * m;
          int64_t count = cnt_query(counters, (x / n) - low);
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(sieve, low, high, prime, wheel[b], counters);
    }

    // For pi_sqrty <= b <= pi_sqrtz
    // Find all hard special leaves: n = primes[b] * primes[l]
    // which satisfy: low <= (x / n) < high
    for (; b <= pi_max; b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min3(x / (prime * low), z / prime, y)];
      int64_t min_hard_leaf = max3(x / (prime * high), y / prime, prime);

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_hard_leaf; l--)
      {
        int64_t n = prime * primes[l];
        int64_t xn = x / n;
        int64_t count = cnt_query(counters, xn - low);
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(sieve, low, high, prime, wheel[b], counters);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves which require
/// a sieve (in order to reduce the memory usage).
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
///
int64_t S2_hard(int64_t x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 vector<int32_t>& pi,
                 vector<int32_t>& primes,
                 vector<int32_t>& lpf,
                 vector<int32_t>& mu,
                 int threads)
{
  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = z + 1;

  S2LoadBalancer loadBalancer(x, y, z, threads);
  int64_t segment_size = loadBalancer.get_min_segment_size();
  int64_t segments_per_thread = 1;
  vector<int64_t> phi_total(pi[min(isqrt(z), y)] + 1, 0);

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_hard_thread(x, y, z, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);
  }

  return S2_total;
}

/// Calculate the contribution of the special leaves.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t z,
           int64_t c,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  int64_t limit = z + 1;
  threads = validate_threads(threads, limit);
  vector<int32_t> pi = generate_pi(y);

  int64_t s2_trivial = S2_trivial(x, y, z, c, threads);
  int64_t s2_easy = S2_easy(x, y, z, c, threads);
  int64_t s2_hard = S2_hard(x, y, z, c, pi, primes, lpf, mu, threads);
  int64_t s2 = s2_trivial + s2_easy + s2_hard;

  return s2;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat_parallel1(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha(x, 0.0017154, -0.0508992, 0.483613, 0.0672202);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t p2 = P2(x, y, threads);

  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = pi_bsearch(primes, y);
  int64_t c = PhiTiny::get_c(y);
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2 = S2(x, y, z, c, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<|endoftext|>


<commit_before>///
/// @file  pi_deleglise_rivat_parallel3.cpp
/// @brief Parallel implementation of the Deleglise-Rivat prime
///        counting algorithm. This implementation is identical to
///        pi_deleglise_rivat_parallel2(x) but uses 128-bit integers.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <int128.hpp>
#include <S1.hpp>
#include "S2.hpp"

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// Calculate the contribution of the special leaves.
/// @pre y > 0 && c > 1
///
int128_t S2(int128_t x,
            int64_t y,
            int64_t z,
            int64_t c,
            int128_t s2_approx,
            int threads)
{
  threads = validate_threads(threads, z);

  int128_t s2_trivial = S2_trivial(x, y, z, c, threads);
  int128_t s2_easy = S2_easy(x, y, z, c, threads);
  int128_t s2_hard_approx = s2_approx - (s2_trivial + s2_easy);
  int128_t s2_hard = S2_hard(x, y, z, c, s2_hard_approx, threads);
  int128_t s2 = s2_trivial + s2_easy + s2_hard;

  return s2;
}

/// alpha is a tuning factor which should grow like (log(x))^3
/// for the Deleglise-Rivat prime counting algorithm.
///
double compute_alpha(int128_t x)
{
  double d = (double) x;
  double alpha = (get_alpha() >= 1) ? get_alpha() : log(d) * log(d) * log(d) / 1200;
  return in_between(1, alpha, iroot<6>(x));
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat_parallel3(int128_t x, int threads)
{
  if (x < 2)
    return 0;

  if (x > to_maxint(primecount::max()))
    throw primecount_error("pi(x): x must be <= " + max());

  double alpha = compute_alpha(x);
  int64_t y = (int64_t) (alpha * iroot<3>(x));
  int64_t z = (int64_t) (x / y);
  int64_t pi_y = pi_legendre(y, 1);
  int64_t c = min(pi_y, PhiTiny::max_a());

  if (print_status())
  {
    cout << endl;
    cout << "=== pi_deleglise_rivat_parallel3(x) ===" << endl;
    cout << "pi(x) = S1 + S2 + pi(y) - 1 - P2" << endl;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "alpha = " << fixed << setprecision(3) << alpha << endl;
    cout << "c = " << c << endl;
    cout << "threads = " << validate_threads(threads) << endl;
  }

  int128_t p2 = P2(x, y, threads);
  int128_t s1 = S1(x, y, c, threads);
  int128_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int128_t s2 = S2(x, y, z, c, s2_approx, threads);
  int128_t phi = s1 + s2;
  int128_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace
<commit_msg>Refactoring<commit_after>///
/// @file  pi_deleglise_rivat_parallel3.cpp
/// @brief Parallel implementation of the Deleglise-Rivat prime
///        counting algorithm. This implementation is identical to
///        pi_deleglise_rivat_parallel2(x) but uses 128-bit integers.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <int128.hpp>
#include <S1.hpp>
#include "S2.hpp"

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// alpha is a tuning factor which should grow like (log(x))^3
/// for the Deleglise-Rivat prime counting algorithm.
///
double compute_alpha(int128_t x)
{
  double d = (double) x;
  double alpha = (get_alpha() >= 1) ? get_alpha() : log(d) * log(d) * log(d) / 1200;
  return in_between(1, alpha, iroot<6>(x));
}

/// Calculate the contribution of the special leaves.
/// @pre y > 0 && c > 1
///
int128_t S2(int128_t x,
            int64_t y,
            int64_t z,
            int64_t c,
            int128_t s2_approx,
            int threads)
{
  int128_t s2_trivial = S2_trivial(x, y, z, c, threads);
  int128_t s2_easy = S2_easy(x, y, z, c, threads);
  int128_t s2_hard_approx = s2_approx - (s2_trivial + s2_easy);
  int128_t s2_hard = S2_hard(x, y, z, c, s2_hard_approx, threads);
  int128_t s2 = s2_trivial + s2_easy + s2_hard;

  return s2;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat_parallel3(int128_t x, int threads)
{
  if (x < 2)
    return 0;

  if (x > to_maxint(primecount::max()))
    throw primecount_error("pi(x): x must be <= " + max());

  double alpha = compute_alpha(x);
  int64_t y = (int64_t) (alpha * iroot<3>(x));
  int64_t z = (int64_t) (x / y);
  int64_t pi_y = pi_legendre(y, 1);
  int64_t c = min(pi_y, PhiTiny::max_a());

  if (print_status())
  {
    cout << endl;
    cout << "=== pi_deleglise_rivat_parallel3(x) ===" << endl;
    cout << "pi(x) = S1 + S2 + pi(y) - 1 - P2" << endl;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
    cout << "alpha = " << fixed << setprecision(3) << alpha << endl;
    cout << "c = " << c << endl;
    cout << "threads = " << validate_threads(threads) << endl;
  }

  int128_t p2 = P2(x, y, threads);
  int128_t s1 = S1(x, y, c, threads);
  int128_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int128_t s2 = S2(x, y, z, c, s2_approx, threads);
  int128_t phi = s1 + s2;
  int128_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace
<|endoftext|>


<commit_before>#include <QMetaOrm/session.h>
#include <QMetaOrm/exceptions.h>
#include <qthread.h>

using namespace QMetaOrm;

QString GetThreadIdentifier() {
   return QString::number((int)QThread::currentThreadId());
}

Session::Session(
   DatabaseFactory::Ptr databaseFactory,
   EntitySqlBuilder::Ptr entitySqlBuilder,
   EntityMapper::Ptr entityMapper,
   ConverterStore::Ptr converterStore)
   : m_database(databaseFactory->createDatabase(GetThreadIdentifier()))
   , m_entitySqlBuilder(entitySqlBuilder)
   , m_entityMapper(entityMapper)
   , m_converterStore(converterStore)
{
}

Session::~Session() {
   m_database.rollback();
   m_database.close();
}

void Session::commit() {
   if (!m_database.commit())
      throw TransactionException(m_database.lastError());
}

void Session::rollback() {
   if (!m_database.rollback())
      throw TransactionException(m_database.lastError());
}

void Session::setupSession() {
   if (m_database.isOpen())
      return;

   if (!m_database.open())
      throw ConnectToDatabaseException(m_database.lastError());

   if (!m_database.transaction())
      throw TransactionException(m_database.lastError());
}
<commit_msg>Sessions should actually not close a connection because others still use it.<commit_after>#include <QMetaOrm/session.h>
#include <QMetaOrm/exceptions.h>
#include <qthread.h>

using namespace QMetaOrm;

QString GetThreadIdentifier() {
   return QString::number((int)QThread::currentThreadId());
}

Session::Session(
   DatabaseFactory::Ptr databaseFactory,
   EntitySqlBuilder::Ptr entitySqlBuilder,
   EntityMapper::Ptr entityMapper,
   ConverterStore::Ptr converterStore)
   : m_database(databaseFactory->createDatabase(GetThreadIdentifier()))
   , m_entitySqlBuilder(entitySqlBuilder)
   , m_entityMapper(entityMapper)
   , m_converterStore(converterStore)
{
}

Session::~Session() {
}

void Session::commit() {
   if (!m_database.commit())
      throw TransactionException(m_database.lastError());
}

void Session::rollback() {
   if (!m_database.rollback())
      throw TransactionException(m_database.lastError());
}

void Session::setupSession() {
   if (m_database.isOpen())
      return;

   if (!m_database.open())
      throw ConnectToDatabaseException(m_database.lastError());

   if (!m_database.transaction())
      throw TransactionException(m_database.lastError());
}
<|endoftext|>


<commit_before>/*************************************
** Tsunagari Tile Engine            **
** window.cpp                       **
** Copyright 2016-2019 Paul Merrill **
*************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include "av/sdl2/window.h"

#include "av/sdl2/error.h"
#include "av/sdl2/sdl2.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/log.h"
#include "core/measure.h"
#include "core/world.h"
#include "util/noexcept.h"
#include "util/optional.h"

SDL_Renderer* SDL2GameWindow::renderer = nullptr;
rvec2 SDL2GameWindow::translation = {0.0, 0.0};
rvec2 SDL2GameWindow::scaling = {0.0, 0.0};

static TimePoint start = SteadyClock::nowMS();

static SDL_Window* window = nullptr;
static Transform transform = Transform::identity();

static int
getRefreshRate(SDL_Window* window) noexcept {
    // SDL_GetWindowDisplayIndex computes which display the window is on each
    // time.
    int display = SDL_GetWindowDisplayIndex(window);
    SDL_DisplayMode mode;
    SDL_GetCurrentDisplayMode(display, &mode);
    return mode.refresh_rate;
}

static void
handleEvent(const SDL_Event& event) noexcept {
    KeyboardKey key;

    switch (event.type) {
    case SDL_KEYUP:
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym) {
        case SDLK_ESCAPE:
            key = KBEscape;
            break;
        case SDLK_LCTRL:
            key = KBLeftControl;
            break;
        case SDLK_RCTRL:
            key = KBRightControl;
            break;
        case SDLK_LSHIFT:
            key = KBLeftShift;
            break;
        case SDLK_RSHIFT:
            key = KBRightShift;
            break;
        case SDLK_SPACE:
            key = KBSpace;
            break;
        case SDLK_LEFT:
            key = KBLeftArrow;
            break;
        case SDLK_RIGHT:
            key = KBRightArrow;
            break;
        case SDLK_UP:
            key = KBUpArrow;
            break;
        case SDLK_DOWN:
            key = KBDownArrow;
            break;
        default:
            return;
        }
        if (event.type == SDL_KEYUP) {
            GameWindow::emitKeyUp(key);
        }
        else if (event.type == SDL_KEYDOWN) {
            GameWindow::emitKeyDown(key);
        }
        break;

    case SDL_QUIT:
        SDL_DestroyWindow(window);
        exit(0);
        return;

    default:
        return;
    }
}

static void
handleEvents() noexcept {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        handleEvent(event);
    }
}

static void
updateTransform() noexcept {
    int w, h;

    SDL_GetWindowSize(window, &w, &h);

    float xScale = transform[0];
    float yScale = transform[5];
    float x = transform[12];
    float y = transform[13];

    SDL2GameWindow::translation = {x / xScale, y / yScale};
    SDL2GameWindow::scaling = {xScale, yScale};
}

time_t
GameWindow::time() noexcept {
    return SteadyClock::nowMS() - start;
}

void
GameWindow::create() noexcept {
    {
        // TimeMeasure m("Initializing SDL2");
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            sdlDie("SDL2GameWindow", "SDL_Init");
        }
    }

    {
        TimeMeasure m("Created SDL2 window");

        int width = Conf::windowSize.x;
        int height = Conf::windowSize.y;

        uint32_t flags = SDL_WINDOW_HIDDEN;
        if (Conf::fullscreen) {
            flags |= SDL_WINDOW_FULLSCREEN;
        }

        window = SDL_CreateWindow("Tsunagari",
                                  SDL_WINDOWPOS_UNDEFINED,
                                  SDL_WINDOWPOS_UNDEFINED,
                                  width,
                                  height,
                                  flags);

        if (window == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateWindow");
        }
    }

    {
        TimeMeasure m("Created SDL2 renderer");

        SDL2GameWindow::renderer = SDL_CreateRenderer(
                window,
                -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if (SDL2GameWindow::renderer == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateRenderer");
        }

        SDL_RendererInfo info;

        if (SDL_GetRendererInfo(SDL2GameWindow::renderer, &info) < 0) {
            sdlDie("SDL2GameWindow", "SDL_GetRendererInfo");
        }

        StringView name = info.name;
        bool vsync = info.flags & SDL_RENDERER_PRESENTVSYNC;

        Log::info("SDL2GameWindow",
                  String("Rendering will be done with ")
                          << name
                          << (vsync ? " with vsync" : " without vsync"));
    }

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0x00, 0x00, 0x00, 0xFF);
}

unsigned
GameWindow::width() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(w);
}

unsigned
GameWindow::height() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(h);
}

void
GameWindow::setCaption(StringView caption) noexcept {
    SDL_SetWindowTitle(window, String(caption).null());
}

void
GameWindow::mainLoop() noexcept {
    SDL_ShowWindow(window);

    DisplayList display;

    int refreshRate = getRefreshRate(window);
    const Duration idealFrameTime = s_to_ns(1) / refreshRate;

	// Block until the start of a frame.
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);

	TimePoint frameStart = SteadyClock::now();
    TimePoint previousFrameStart =
            frameStart - idealFrameTime;  // Bogus initial value.

    TimePoint nextFrameStart = frameStart + idealFrameTime;

	while (window != nullptr) {
        handleEvents();

		//
        // Simulate world and draw frame.
        //
        time_t dt = ns_to_ms(frameStart - previousFrameStart);

		assert_(dt >= 0);

		if (dt > 0) {
            World::tick(dt);
        } else {
            Log::info("SDL2GameWindow", "dt == 0");
        }

		bool drew = false;
        if (World::needsRedraw()) {
            drew = true;

            World::draw(&display);

            SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
            SDL_RenderClear(SDL2GameWindow::renderer);
            displayListPresent(&display);
            SDL_RenderPresent(SDL2GameWindow::renderer);

            display.items.clear();
        }

        TimePoint frameEnd = SteadyClock::now();
        Duration timeTaken = frameEnd - frameStart;

        //
        // Sleep until next frame.
        //
        Duration sleepDuration = nextFrameStart - frameEnd;
        if (sleepDuration < 0) {
            sleepDuration = 0;
        }

        if (!drew && sleepDuration) {
            SleepFor(sleepDuration);
        }

        previousFrameStart = frameStart;
        frameStart = SteadyClock::now();
        nextFrameStart += idealFrameTime;

        if (frameStart > nextFrameStart) {
            int framesDropped = 0;
            while (frameStart > nextFrameStart) {
                nextFrameStart += idealFrameTime;
                framesDropped += 1;
            }
            Log::info("GameWindow",
                      String() << "Dropped " << framesDropped << " frames");
        }
    }
}

void
GameWindow::drawRect(float x1,
                     float x2,
                     float y1,
                     float y2,
                     uint32_t argb) noexcept {
    auto a = static_cast<uint8_t>((argb >> 24) & 0xFF);
    auto r = static_cast<uint8_t>((argb >> 16) & 0xFF);
    auto g = static_cast<uint8_t>((argb >> 8) & 0xFF);
    auto b = static_cast<uint8_t>((argb >> 0) & 0xFF);

    SDL_Rect rect{static_cast<int>(x1),
                  static_cast<int>(y1),
                  static_cast<int>(x2 - x1),
                  static_cast<int>(y2 - y1)};

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, r, g, b, a);
    SDL_SetRenderDrawBlendMode(SDL2GameWindow::renderer, SDL_BLENDMODE_BLEND);
    SDL_RenderFillRect(SDL2GameWindow::renderer, &rect);
}

void
GameWindow::scale(float x, float y, Function<void()> op) noexcept {
    assert_(x == y);

    Transform prev = transform;

    auto factor = static_cast<float>(x);

    transform = Transform::scale(factor) * transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::translate(float x, float y, Function<void()> op) noexcept {
    Transform prev = transform;

    transform =
            Transform::translate(static_cast<float>(x), static_cast<float>(y)) *
            transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::clip(float x,
                 float y,
                 float width,
                 float height,
                 Function<void()> op) noexcept {
    op();
}

void
GameWindow::close() noexcept {
    SDL_DestroyWindow(window);
    window = nullptr;
}
<commit_msg>av/sdl2/window: Whitespace<commit_after>/*************************************
** Tsunagari Tile Engine            **
** window.cpp                       **
** Copyright 2016-2019 Paul Merrill **
*************************************/

// **********
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// **********

#include "av/sdl2/window.h"

#include "av/sdl2/error.h"
#include "av/sdl2/sdl2.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/log.h"
#include "core/measure.h"
#include "core/world.h"
#include "util/noexcept.h"
#include "util/optional.h"

SDL_Renderer* SDL2GameWindow::renderer = nullptr;
rvec2 SDL2GameWindow::translation = {0.0, 0.0};
rvec2 SDL2GameWindow::scaling = {0.0, 0.0};

static TimePoint start = SteadyClock::nowMS();

static SDL_Window* window = nullptr;
static Transform transform = Transform::identity();

static int
getRefreshRate(SDL_Window* window) noexcept {
    // SDL_GetWindowDisplayIndex computes which display the window is on each
    // time.
    int display = SDL_GetWindowDisplayIndex(window);
    SDL_DisplayMode mode;
    SDL_GetCurrentDisplayMode(display, &mode);
    return mode.refresh_rate;
}

static void
handleEvent(const SDL_Event& event) noexcept {
    KeyboardKey key;

    switch (event.type) {
    case SDL_KEYUP:
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym) {
        case SDLK_ESCAPE:
            key = KBEscape;
            break;
        case SDLK_LCTRL:
            key = KBLeftControl;
            break;
        case SDLK_RCTRL:
            key = KBRightControl;
            break;
        case SDLK_LSHIFT:
            key = KBLeftShift;
            break;
        case SDLK_RSHIFT:
            key = KBRightShift;
            break;
        case SDLK_SPACE:
            key = KBSpace;
            break;
        case SDLK_LEFT:
            key = KBLeftArrow;
            break;
        case SDLK_RIGHT:
            key = KBRightArrow;
            break;
        case SDLK_UP:
            key = KBUpArrow;
            break;
        case SDLK_DOWN:
            key = KBDownArrow;
            break;
        default:
            return;
        }
        if (event.type == SDL_KEYUP) {
            GameWindow::emitKeyUp(key);
        }
        else if (event.type == SDL_KEYDOWN) {
            GameWindow::emitKeyDown(key);
        }
        break;

    case SDL_QUIT:
        SDL_DestroyWindow(window);
        exit(0);
        return;

    default:
        return;
    }
}

static void
handleEvents() noexcept {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        handleEvent(event);
    }
}

static void
updateTransform() noexcept {
    int w, h;

    SDL_GetWindowSize(window, &w, &h);

    float xScale = transform[0];
    float yScale = transform[5];
    float x = transform[12];
    float y = transform[13];

    SDL2GameWindow::translation = {x / xScale, y / yScale};
    SDL2GameWindow::scaling = {xScale, yScale};
}

time_t
GameWindow::time() noexcept {
    return SteadyClock::nowMS() - start;
}

void
GameWindow::create() noexcept {
    {
        // TimeMeasure m("Initializing SDL2");
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            sdlDie("SDL2GameWindow", "SDL_Init");
        }
    }

    {
        TimeMeasure m("Created SDL2 window");

        int width = Conf::windowSize.x;
        int height = Conf::windowSize.y;

        uint32_t flags = SDL_WINDOW_HIDDEN;
        if (Conf::fullscreen) {
            flags |= SDL_WINDOW_FULLSCREEN;
        }

        window = SDL_CreateWindow("Tsunagari",
                                  SDL_WINDOWPOS_UNDEFINED,
                                  SDL_WINDOWPOS_UNDEFINED,
                                  width,
                                  height,
                                  flags);

        if (window == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateWindow");
        }
    }

    {
        TimeMeasure m("Created SDL2 renderer");

        SDL2GameWindow::renderer = SDL_CreateRenderer(
                window,
                -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if (SDL2GameWindow::renderer == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateRenderer");
        }

        SDL_RendererInfo info;

        if (SDL_GetRendererInfo(SDL2GameWindow::renderer, &info) < 0) {
            sdlDie("SDL2GameWindow", "SDL_GetRendererInfo");
        }

        StringView name = info.name;
        bool vsync = info.flags & SDL_RENDERER_PRESENTVSYNC;

        Log::info("SDL2GameWindow",
                  String("Rendering will be done with ")
                          << name
                          << (vsync ? " with vsync" : " without vsync"));
    }

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0x00, 0x00, 0x00, 0xFF);
}

unsigned
GameWindow::width() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(w);
}

unsigned
GameWindow::height() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(h);
}

void
GameWindow::setCaption(StringView caption) noexcept {
    SDL_SetWindowTitle(window, String(caption).null());
}

void
GameWindow::mainLoop() noexcept {
    SDL_ShowWindow(window);

    DisplayList display;

    int refreshRate = getRefreshRate(window);
    const Duration idealFrameTime = s_to_ns(1) / refreshRate;

    // Block until the start of a frame.
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);

    TimePoint frameStart = SteadyClock::now();
    TimePoint previousFrameStart =
            frameStart - idealFrameTime;  // Bogus initial value.

    TimePoint nextFrameStart = frameStart + idealFrameTime;

    while (window != nullptr) {
        handleEvents();

        //
        // Simulate world and draw frame.
        //
        time_t dt = ns_to_ms(frameStart - previousFrameStart);

        assert_(dt >= 0);

        if (dt > 0) {
            World::tick(dt);
        } else {
            Log::info("SDL2GameWindow", "dt == 0");
        }

        bool drew = false;
        if (World::needsRedraw()) {
            drew = true;

            World::draw(&display);

            SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
            SDL_RenderClear(SDL2GameWindow::renderer);
            displayListPresent(&display);
            SDL_RenderPresent(SDL2GameWindow::renderer);

            display.items.clear();
        }

        TimePoint frameEnd = SteadyClock::now();
        Duration timeTaken = frameEnd - frameStart;

        //
        // Sleep until next frame.
        //
        Duration sleepDuration = nextFrameStart - frameEnd;
        if (sleepDuration < 0) {
            sleepDuration = 0;
        }

        if (!drew && sleepDuration) {
            SleepFor(sleepDuration);
        }

        previousFrameStart = frameStart;
        frameStart = SteadyClock::now();
        nextFrameStart += idealFrameTime;

        if (frameStart > nextFrameStart) {
            int framesDropped = 0;
            while (frameStart > nextFrameStart) {
                nextFrameStart += idealFrameTime;
                framesDropped += 1;
            }
            Log::info("GameWindow",
                      String() << "Dropped " << framesDropped << " frames");
        }
    }
}

void
GameWindow::drawRect(float x1,
                     float x2,
                     float y1,
                     float y2,
                     uint32_t argb) noexcept {
    auto a = static_cast<uint8_t>((argb >> 24) & 0xFF);
    auto r = static_cast<uint8_t>((argb >> 16) & 0xFF);
    auto g = static_cast<uint8_t>((argb >> 8) & 0xFF);
    auto b = static_cast<uint8_t>((argb >> 0) & 0xFF);

    SDL_Rect rect{static_cast<int>(x1),
                  static_cast<int>(y1),
                  static_cast<int>(x2 - x1),
                  static_cast<int>(y2 - y1)};

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, r, g, b, a);
    SDL_SetRenderDrawBlendMode(SDL2GameWindow::renderer, SDL_BLENDMODE_BLEND);
    SDL_RenderFillRect(SDL2GameWindow::renderer, &rect);
}

void
GameWindow::scale(float x, float y, Function<void()> op) noexcept {
    assert_(x == y);

    Transform prev = transform;

    auto factor = static_cast<float>(x);

    transform = Transform::scale(factor) * transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::translate(float x, float y, Function<void()> op) noexcept {
    Transform prev = transform;

    transform =
            Transform::translate(static_cast<float>(x), static_cast<float>(y)) *
            transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::clip(float x,
                 float y,
                 float width,
                 float height,
                 Function<void()> op) noexcept {
    op();
}

void
GameWindow::close() noexcept {
    SDL_DestroyWindow(window);
    window = nullptr;
}
<|endoftext|>


<commit_before>#include <ostream>
#include <gtest/gtest.h>
#include "KeyCode.hpp"
#include "ButtonStatus.hpp"
#include "Config.hpp"

using namespace org_pqrs_KeyRemap4MacBook;
Config config;

std::ostream& operator<<(std::ostream& os, const EventType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyboardType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ModifierFlag& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Flags& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ConsumerKeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const PointingButton& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Buttons& v) { return os << v.get(); }

TEST(ButtonStatus, all) {
  ASSERT_TRUE(ButtonStatus::initialize());

  EXPECT_EQ(Buttons(), ButtonStatus::makeButtons());

  // ------------------------------------------------------------
  // set
  {
    Buttons justPressed(1 << 3);
    Buttons justReleased(1 << 11);
    ButtonStatus::set(justPressed, justReleased);
    EXPECT_EQ(Buttons((1 << 3)), ButtonStatus::makeButtons());

    justPressed = Buttons(1 << 11);
    justReleased = Buttons(0);
    ButtonStatus::set(justPressed, justReleased);
    EXPECT_EQ(Buttons((1 << 3)), ButtonStatus::makeButtons());

    justPressed = Buttons(1 << 11);
    justReleased = Buttons(0);
    ButtonStatus::set(justPressed, justReleased);
    EXPECT_EQ(Buttons((1 << 3) | (1 << 11)), ButtonStatus::makeButtons());

    justPressed = Buttons(0);
    justReleased = Buttons(1 << 3);
    ButtonStatus::set(justPressed, justReleased);
    EXPECT_EQ(Buttons((1 << 11)), ButtonStatus::makeButtons());

    justPressed = Buttons(1 << 1);
    justReleased = Buttons(0);
    ButtonStatus::set(justPressed, justReleased);
    EXPECT_EQ(Buttons((1 << 1) | (1 << 11)), ButtonStatus::makeButtons());
  }

  // ------------------------------------------------------------
  // increase & decrease
  ButtonStatus::increase(1 << 9);
  EXPECT_EQ(Buttons((1 << 1) | (1 << 9) | (1 << 11)), ButtonStatus::makeButtons());

  ButtonStatus::decrease((1 << 4) | (1 << 8));
  EXPECT_EQ(Buttons((1 << 1) | (1 << 9) | (1 << 11)), ButtonStatus::makeButtons());

  // ------------------------------------------------------------
  // reset
  ButtonStatus::reset();
  EXPECT_EQ(Buttons(), ButtonStatus::makeButtons());
}
<commit_msg>update Tests/kext/ButtonStatus/test.cpp<commit_after>#include <ostream>
#include <gtest/gtest.h>
#include "KeyCode.hpp"
#include "ButtonStatus.hpp"
#include "Config.hpp"

using namespace org_pqrs_KeyRemap4MacBook;
Config config;

std::ostream& operator<<(std::ostream& os, const EventType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyboardType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ModifierFlag& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Flags& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ConsumerKeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const PointingButton& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Buttons& v) { return os << v.get(); }

TEST(ButtonStatus, all) {
  ASSERT_TRUE(ButtonStatus::initialize());

  EXPECT_EQ(Buttons(), ButtonStatus::makeButtons());

  // ------------------------------------------------------------
  // set
  {
    ButtonStatus::set((1 << 3), true);
    EXPECT_EQ(Buttons((1 << 3)), ButtonStatus::makeButtons());

    ButtonStatus::set((1 << 11), false);
    EXPECT_EQ(Buttons((1 << 3)), ButtonStatus::makeButtons());

    ButtonStatus::set((1 << 11), true);
    EXPECT_EQ(Buttons((1 << 3)), ButtonStatus::makeButtons());

    ButtonStatus::set((1 << 11), true);
    EXPECT_EQ(Buttons((1 << 3) | (1 << 11)), ButtonStatus::makeButtons());

    ButtonStatus::set((1 << 3), false);
    EXPECT_EQ(Buttons((1 << 11)), ButtonStatus::makeButtons());

    ButtonStatus::set((1 << 1), true);
    EXPECT_EQ(Buttons((1 << 1) | (1 << 11)), ButtonStatus::makeButtons());
  }

  // ------------------------------------------------------------
  // increase & decrease
  ButtonStatus::increase(1 << 9);
  EXPECT_EQ(Buttons((1 << 1) | (1 << 9) | (1 << 11)), ButtonStatus::makeButtons());

  ButtonStatus::decrease((1 << 4) | (1 << 8));
  EXPECT_EQ(Buttons((1 << 1) | (1 << 9) | (1 << 11)), ButtonStatus::makeButtons());

  // ------------------------------------------------------------
  // reset
  ButtonStatus::reset();
  EXPECT_EQ(Buttons(), ButtonStatus::makeButtons());
}
<|endoftext|>


<commit_before><commit_msg>Add snapshot of generic/memory for master-p10<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2015 by Philip N. Garner
 *
 * See the file COPYING for the licence associated with this software.
 *
 * Author(s):
 *   Phil Garner, May 2015
 */

#include <unistd.h>

#include "lube/module.h"
#include "lube/config.h"

using namespace libube;

Option::Option()
{
    optind = 1; // Resets getopt.  This class should be a singleton.
    mArgc = 0;
    mArgv = 0;
    mOptString = "";
    mOpt = -1;
}

Option::Option(int iArgc, char** iArgv, var iOptString) : Option()
{
    mArgc = iArgc;
    mArgv = iArgv;
    mOptString = iOptString ? iOptString : "";
}

Option::Option(var iName) : Option()
{
    mName = iName;
}

/**
 * A kind of trick: The getopt() call is issued by evaluating the class in a
 * boolean context.  This is basically a while (opt) call, which is pretty much
 * what you want.  The expression to put in the switch() is then opt.get(); no
 * temporary variables should be needed.
 */
Option::operator bool()
{
    // Should be const, but .str() isn't, so something is wrong.
    mOpt = getopt(mArgc, mArgv, mOptString.str());
    return mOpt != -1;
}

// Could we just evaluate the class in an ind context?
ind Option::index() const
{
    return optind;
}

var Option::arg() const
{
    if (!optarg)
    {
        varstream e;
        e << "at argument " << mOpt << " optarg is null";
        throw error(e);
    }
    return optarg;
};

var Option::args()
{
    return var(mArgc-optind, mArgv+optind);
};

void Option::operator ()(char iChar, var iDescription, var iDefault)
{
    mOpts[var(iChar)] = iDefault;
    mOptString.push(iChar);
    if (iDefault)
        mOptString.push(':');
    varstream desc;
    desc << " -" << iChar << " " << iDescription.str();
    if (iDefault)
        desc << " [" << iDefault << "]";
    mUsage.push(var(desc));
}

void Option::operator ()(var iDescription)
{
    mUsage.push(iDescription.str());
}

var Option::parse(int iArgc, char** iArgv)
{
    mArgc = iArgc;
    mArgv = iArgv;
    while (*this)
    {
        var o = (char)get();
        if (o == '?')
            usage(0);
        var a = mOpts[o] ? arg() : 1;
        mOpts[o] = a;
    }
    return mOpts;
}

void Option::usage()
{
    std::cout
        << mName.str() << "\n" << "Usage: " << mArgv[0];
    if (mOptString != "")
        std::cout << " -[" << mOptString.str() << "]";
    std::cout << " [args] (see 'man 3 getopt')\n";
    for (int i=0; i<mUsage.size(); i++)
        std::cout << mUsage[i].str() << "\n";
}

Config::Config(var iStr)
{
    mStr = iStr.copy();
}

void Config::read(var iConfigFile)
{
    // Config files are .ini format
    filemodule im("ini");
    file& ini = im.create();
    mCnf = ini.read(iConfigFile);
}

var Config::config()
{
    // If it doesn't exist, this will make the [mStr] entry
    if (mStr)
        return mCnf[mStr];
    return mCnf["Main"];
}
<commit_msg>Make the default configuration static; successive configs accumulate<commit_after>/*
 * Copyright 2015 by Philip N. Garner
 *
 * See the file COPYING for the licence associated with this software.
 *
 * Author(s):
 *   Phil Garner, May 2015
 */

#include <unistd.h>

#include "lube/module.h"
#include "lube/config.h"

using namespace libube;

Option::Option()
{
    optind = 1; // Resets getopt.  This class should be a singleton.
    mArgc = 0;
    mArgv = 0;
    mOptString = "";
    mOpt = -1;
}

Option::Option(int iArgc, char** iArgv, var iOptString) : Option()
{
    mArgc = iArgc;
    mArgv = iArgv;
    mOptString = iOptString ? iOptString : "";
}

Option::Option(var iName) : Option()
{
    mName = iName;
}

/**
 * A kind of trick: The getopt() call is issued by evaluating the class in a
 * boolean context.  This is basically a while (opt) call, which is pretty much
 * what you want.  The expression to put in the switch() is then opt.get(); no
 * temporary variables should be needed.
 */
Option::operator bool()
{
    // Should be const, but .str() isn't, so something is wrong.
    mOpt = getopt(mArgc, mArgv, mOptString.str());
    return mOpt != -1;
}

// Could we just evaluate the class in an ind context?
ind Option::index() const
{
    return optind;
}

var Option::arg() const
{
    if (!optarg)
    {
        varstream e;
        e << "at argument " << mOpt << " optarg is null";
        throw error(e);
    }
    return optarg;
};

var Option::args()
{
    return var(mArgc-optind, mArgv+optind);
};

void Option::operator ()(char iChar, var iDescription, var iDefault)
{
    mOpts[var(iChar)] = iDefault;
    mOptString.push(iChar);
    if (iDefault)
        mOptString.push(':');
    varstream desc;
    desc << " -" << iChar << " " << iDescription.str();
    if (iDefault)
        desc << " [" << iDefault << "]";
    mUsage.push(var(desc));
}

void Option::operator ()(var iDescription)
{
    mUsage.push(iDescription.str());
}

var Option::parse(int iArgc, char** iArgv)
{
    mArgc = iArgc;
    mArgv = iArgv;
    while (*this)
    {
        var o = (char)get();
        if (o == '?')
            usage(0);
        var a = mOpts[o] ? arg() : 1;
        mOpts[o] = a;
    }
    return mOpts;
}

void Option::usage()
{
    std::cout
        << mName.str() << "\n" << "Usage: " << mArgv[0];
    if (mOptString != "")
        std::cout << " -[" << mOptString.str() << "]";
    std::cout << " [args] (see 'man 3 getopt')\n";
    for (int i=0; i<mUsage.size(); i++)
        std::cout << mUsage[i].str() << "\n";
}

/**
 * Static config.  This functions as a global config that gets used if no other
 * is specified.
 */
namespace libube
{
    static var sConfig;
}

/**
 * Config constructor
 *
 * By default, it uses the static (global) config
 */
Config::Config(var iStr)
{
    // Make sure sConfig is an associative array so we copy the reference
    if (!sConfig)
        sConfig[nil];
    mCnf = sConfig;
    mStr = iStr.copy();
}

void Config::read(var iConfigFile)
{
    // Config files are .ini format
    filemodule im("ini");
    file& ini = im.create();
    var cnf = ini.read(iConfigFile);

    // Merge the new config into the current one
    for (int i=0; i<cnf.size(); i++)
    {
        var seckey = cnf.key(i);
        var secval = cnf[i];
        for (int j=0; j<secval.size(); j++)
        {
            var entry = secval.key(j);
            mCnf[seckey][entry] = secval[entry];
        }
    }
}

var Config::config()
{
    // If it doesn't exist, this will make the [mStr] entry
    if (mStr)
        return mCnf[mStr];
    return mCnf["Main"];
}
<|endoftext|>


<commit_before>static int cmp(int a, int b);

#include "../src/vector_brodnik.h"
#include "../src/vector_bagwell.h"
#include "../src/vector_block.h"
#include "../src/vector_realloc.h"
#include "../src/vector_malloc.h"
#include "../src/losertree.h"
#include "../src/routines.h"
#include "../src/util/insertion_sort.h"
#include <iostream>
#include <array>
#include <vector>
#include <utility>

#undef NDEBUG
#include <cassert>

template <typename Container>
void test_basics()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		Container v;
		assert(v.size()==0);
	}
	{
		Container v;
		v.push_back(1);
		assert(v.size()==1);
		assert(v[0]==1);
	}
	{
		Container v;
		const unsigned N=1000000;
		for (unsigned i=0; i < N; ++i) {
			assert(v.size()==i);
			v.push_back(i);
			assert(unsigned(v[i])==i);
		}
		assert(v.size()==N);
	}
	{
		Container v;
		const unsigned N=1000000;
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
	}
}

static int cmp(int a, int b)
{
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

static void
test_loser_tree()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		std::array<int, 5> seq1 = { 2, 4, 6, 8, 10 };
		std::array<int, 5> seq2 = { 3, 5, 7, 9, 11 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq1.data(), 5));
		seqs.push_back(std::make_pair(seq2.data(), 5));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 2);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 1);
		assert(tree.min() == 11); assert(tree._nonempty_streams == 0);
	}
	{
		std::array<int, 3> seq1 = { 2, 5, 8  };
		std::array<int, 3> seq2 = { 3, 6, 9  };
		std::array<int, 3> seq3 = { 4, 7, 10 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq1.data(), 3));
		seqs.push_back(std::make_pair(seq2.data(), 3));
		seqs.push_back(std::make_pair(seq3.data(), 3));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 3);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 1);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 0);
	}
	{
		std::array<int, 3> seq1 = { 2, 5, 8  };
		std::array<int, 3> seq2 = { 3, 6, 9  };
		std::array<int, 3> seq3 = { 4, 7, 10 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq3.data(), 3));
		seqs.push_back(std::make_pair(seq2.data(), 3));
		seqs.push_back(std::make_pair(seq1.data(), 3));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 3);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 1);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 0);
	}
	{
		const unsigned items = 32;
		std::vector<std::vector<int> > data(25000);
		for (unsigned i=0; i < data.size(); ++i) {
			for (unsigned j=0; j < items; ++j) {
				data[i].push_back(j);
			}
		}
		std::vector<std::pair<int*, size_t> > seqs;
		for (unsigned i=0; i < data.size(); ++i) {
			seqs.push_back(std::make_pair(data[i].data(), items));
		}
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == data.size());
		for (unsigned i=0; i < items; ++i) {
			for (unsigned j=0; j < data.size(); ++j) {
				assert(tree.min() == int(i));
			}
		}
		assert(tree._nonempty_streams == 0);
	}
}

static void
test_insertion_sort()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		std::array<const char *, 0> input;
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
	}
	{
		std::array<const char *, 1> input = {""};
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
	}
	{
		std::array<const char *, 5> input = {
			"c",
			"",
			"bbaaa",
			"aaaaa",
			"bbbbb",
		};
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
		assert(strcmp(input[0], "") == 0);
		assert(strcmp(input[1], "aaaaa") == 0);
		assert(strcmp(input[2], "bbaaa") == 0);
		assert(strcmp(input[3], "bbbbb") == 0);
		assert(strcmp(input[4], "c") == 0);
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
		assert(strcmp(input[0], "") == 0);
		assert(strcmp(input[1], "aaaaa") == 0);
		assert(strcmp(input[2], "bbaaa") == 0);
		assert(strcmp(input[3], "bbbbb") == 0);
		assert(strcmp(input[4], "c") == 0);
	}
	{
		std::array<const char *, 3> input = {
			"bbbb1",
			"aaaa3",
			"aaaa2",
		};
		insertion_sort((unsigned char **)input.data(), input.size(), 4);
		assert(strcmp(input[0], "bbbb1") == 0);
		assert(strcmp(input[1], "aaaa2") == 0);
		assert(strcmp(input[2], "aaaa3") == 0);
	}
}

static void
test_routines()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;

	const struct routine **routines;
	unsigned routines_cnt;
	routine_get_all(&routines, &routines_cnt);

	for (unsigned i=0; i < routines_cnt; ++i) {
		std::cerr << "- " << routines[i]->name << '\n';

		{
			std::vector<char *> input;
			for (size_t i=0; i < 1500; ++i)
				input.push_back(strdup("aaa"));

			const size_t n = input.size();
			routines[i]->f((unsigned char **)input.data(), n);

			for (size_t i=0; i < n; ++i)
				assert(strcmp(input[i], "aaa") == 0);
			assert(check_result((unsigned char**)input.data(), n) == 0);
			for (size_t i=0; i < n; ++i)
				free(input[i]);
		}
		{
			std::vector<char *> input;
			for (size_t i=0; i < 300; ++i) {
				input.push_back(strdup("a"));
				input.push_back(strdup("bb"));
				input.push_back(strdup("bbb"));
			}

			const size_t n = input.size();
			routines[i]->f((unsigned char **)input.data(), n);

			for (size_t i=0*(n/3); i < 1*(n/3); ++i)
				assert(strcmp(input[i], "a") == 0);
			for (size_t i=1*(n/3); i < 2*(n/3); ++i)
				assert(strcmp(input[i], "bb") == 0);
			for (size_t i=2*(n/3); i < 3*(n/3); ++i)
				assert(strcmp(input[i], "bbb") == 0);
			assert(check_result((unsigned char**)input.data(), n) == 0);
			for (size_t i=0; i < n; ++i)
				free(input[i]);
		}
	}
}

struct OK { ~OK() { std::cerr << "*** All OK ***\n"; } };

int main()
{
	OK ok;
	/*********************************************************/
	test_loser_tree();
	/*********************************************************/
	test_basics<vector_brodnik<int> >();
	test_basics<vector_bagwell<int> >();
	test_basics<vector_block<int> >();
	test_basics<vector_malloc<int> >();
	test_basics<vector_malloc_counter_clear<int> >();
	test_basics<vector_realloc<int> >();
	test_basics<vector_realloc_counter_clear<int> >();
	test_basics<vector_realloc_shrink_clear<int> >();
	/*********************************************************/
	test_basics<vector_brodnik<uint64_t> >();
	test_basics<vector_bagwell<uint64_t> >();
	test_basics<vector_block<uint64_t> >();
	test_basics<vector_malloc<uint64_t> >();
	test_basics<vector_malloc_counter_clear<uint64_t> >();
	test_basics<vector_realloc<uint64_t> >();
	test_basics<vector_realloc_counter_clear<uint64_t> >();
	test_basics<vector_realloc_shrink_clear<uint64_t> >();
	/*********************************************************/
	test_insertion_sort();
	/*********************************************************/
	test_routines();
	/*********************************************************/
}
<commit_msg>unit-test: extend test_routines()<commit_after>static int cmp(int a, int b);

#include "../src/vector_brodnik.h"
#include "../src/vector_bagwell.h"
#include "../src/vector_block.h"
#include "../src/vector_realloc.h"
#include "../src/vector_malloc.h"
#include "../src/losertree.h"
#include "../src/routines.h"
#include "../src/util/insertion_sort.h"
#include <iostream>
#include <array>
#include <vector>
#include <utility>

#undef NDEBUG
#include <cassert>

template <typename Container>
void test_basics()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		Container v;
		assert(v.size()==0);
	}
	{
		Container v;
		v.push_back(1);
		assert(v.size()==1);
		assert(v[0]==1);
	}
	{
		Container v;
		const unsigned N=1000000;
		for (unsigned i=0; i < N; ++i) {
			assert(v.size()==i);
			v.push_back(i);
			assert(unsigned(v[i])==i);
		}
		assert(v.size()==N);
	}
	{
		Container v;
		const unsigned N=1000000;
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
		for (unsigned i=0; i < N; ++i) v.push_back(i);
		for (unsigned i=0; i < N; ++i) assert(unsigned(v[i])==i);
		v.clear();
		assert(v.size()==0);
	}
}

static int cmp(int a, int b)
{
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

static void
test_loser_tree()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		std::array<int, 5> seq1 = { 2, 4, 6, 8, 10 };
		std::array<int, 5> seq2 = { 3, 5, 7, 9, 11 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq1.data(), 5));
		seqs.push_back(std::make_pair(seq2.data(), 5));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 2);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 1);
		assert(tree.min() == 11); assert(tree._nonempty_streams == 0);
	}
	{
		std::array<int, 3> seq1 = { 2, 5, 8  };
		std::array<int, 3> seq2 = { 3, 6, 9  };
		std::array<int, 3> seq3 = { 4, 7, 10 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq1.data(), 3));
		seqs.push_back(std::make_pair(seq2.data(), 3));
		seqs.push_back(std::make_pair(seq3.data(), 3));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 3);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 1);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 0);
	}
	{
		std::array<int, 3> seq1 = { 2, 5, 8  };
		std::array<int, 3> seq2 = { 3, 6, 9  };
		std::array<int, 3> seq3 = { 4, 7, 10 };
		std::vector<std::pair<int*, size_t> > seqs;
		seqs.push_back(std::make_pair(seq3.data(), 3));
		seqs.push_back(std::make_pair(seq2.data(), 3));
		seqs.push_back(std::make_pair(seq1.data(), 3));
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == 3);
		assert(tree.min() == 2);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 3);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 4);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 5);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 6);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 7);  assert(tree._nonempty_streams == 3);
		assert(tree.min() == 8);  assert(tree._nonempty_streams == 2);
		assert(tree.min() == 9);  assert(tree._nonempty_streams == 1);
		assert(tree.min() == 10); assert(tree._nonempty_streams == 0);
	}
	{
		const unsigned items = 32;
		std::vector<std::vector<int> > data(25000);
		for (unsigned i=0; i < data.size(); ++i) {
			for (unsigned j=0; j < items; ++j) {
				data[i].push_back(j);
			}
		}
		std::vector<std::pair<int*, size_t> > seqs;
		for (unsigned i=0; i < data.size(); ++i) {
			seqs.push_back(std::make_pair(data[i].data(), items));
		}
		loser_tree<int> tree(seqs.begin(), seqs.end());
		assert(tree._nonempty_streams == data.size());
		for (unsigned i=0; i < items; ++i) {
			for (unsigned j=0; j < data.size(); ++j) {
				assert(tree.min() == int(i));
			}
		}
		assert(tree._nonempty_streams == 0);
	}
}

static void
test_insertion_sort()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;
	{
		std::array<const char *, 0> input;
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
	}
	{
		std::array<const char *, 1> input = {""};
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
	}
	{
		std::array<const char *, 5> input = {
			"c",
			"",
			"bbaaa",
			"aaaaa",
			"bbbbb",
		};
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
		assert(strcmp(input[0], "") == 0);
		assert(strcmp(input[1], "aaaaa") == 0);
		assert(strcmp(input[2], "bbaaa") == 0);
		assert(strcmp(input[3], "bbbbb") == 0);
		assert(strcmp(input[4], "c") == 0);
		insertion_sort((unsigned char **)input.data(), input.size(), 0);
		assert(strcmp(input[0], "") == 0);
		assert(strcmp(input[1], "aaaaa") == 0);
		assert(strcmp(input[2], "bbaaa") == 0);
		assert(strcmp(input[3], "bbbbb") == 0);
		assert(strcmp(input[4], "c") == 0);
	}
	{
		std::array<const char *, 3> input = {
			"bbbb1",
			"aaaa3",
			"aaaa2",
		};
		insertion_sort((unsigned char **)input.data(), input.size(), 4);
		assert(strcmp(input[0], "bbbb1") == 0);
		assert(strcmp(input[1], "aaaa2") == 0);
		assert(strcmp(input[2], "aaaa3") == 0);
	}
}

static void
test_routines()
{
	std::cerr<<__PRETTY_FUNCTION__<<std::endl;

	const struct routine **routines;
	unsigned routines_cnt;
	routine_get_all(&routines, &routines_cnt);

	for (unsigned i=0; i < routines_cnt; ++i) {
		std::cerr << __PRETTY_FUNCTION__
			<< " [" << routines[i]->name << ']' << std::endl;

		for (size_t k=1; k < 2000; k += 200) {
			std::vector<char *> input;
			for (size_t i=0; i < k; ++i)
				input.push_back(strdup("aaa"));

			const size_t n = input.size();
			routines[i]->f((unsigned char **)input.data(), n);

			for (size_t i=0; i < n; ++i)
				assert(strcmp(input[i], "aaa") == 0);
			assert(check_result((unsigned char**)input.data(), n) == 0);
			for (size_t i=0; i < n; ++i)
				free(input[i]);
		}
		for (size_t k=1; k < 1000; k += 200) {
			std::vector<char *> input;
			for (size_t i=0; i < k; ++i) {
				input.push_back(strdup("bb"));
				input.push_back(strdup("a"));
				input.push_back(strdup("bbb"));
			}

			const size_t n = input.size();
			routines[i]->f((unsigned char **)input.data(), n);

			for (size_t i=0*(n/3); i < 1*(n/3); ++i)
				assert(strcmp(input[i], "a") == 0);
			for (size_t i=1*(n/3); i < 2*(n/3); ++i)
				assert(strcmp(input[i], "bb") == 0);
			for (size_t i=2*(n/3); i < 3*(n/3); ++i)
				assert(strcmp(input[i], "bbb") == 0);
			assert(check_result((unsigned char**)input.data(), n) == 0);
			for (size_t i=0; i < n; ++i)
				free(input[i]);
		}
		for (size_t k=1; k < 10000; k += 2000) {
			std::vector<char *> input;
			for (size_t i=0; i < k; ++i) {
				char buf[10];
				memset(buf, 'a'+(i%30), sizeof(buf)-1);
				buf[sizeof(buf)-1] = 0;
				input.push_back(strdup(buf));
			}

			const size_t n = input.size();
			routines[i]->f((unsigned char **)input.data(), n);
			// for (size_t i=0; i < n; ++i) std::cerr<<input[i]<<'\n';
			assert(check_result((unsigned char**)input.data(), n) == 0);
			for (size_t i=0; i < n; ++i)
				free(input[i]);
		}
	}
}

struct OK { ~OK() { std::cerr << "*** All OK ***\n"; } };

int main()
{
	OK ok;
	/*********************************************************/
	test_loser_tree();
	/*********************************************************/
	test_basics<vector_brodnik<int> >();
	test_basics<vector_bagwell<int> >();
	test_basics<vector_block<int> >();
	test_basics<vector_malloc<int> >();
	test_basics<vector_malloc_counter_clear<int> >();
	test_basics<vector_realloc<int> >();
	test_basics<vector_realloc_counter_clear<int> >();
	test_basics<vector_realloc_shrink_clear<int> >();
	/*********************************************************/
	test_basics<vector_brodnik<uint64_t> >();
	test_basics<vector_bagwell<uint64_t> >();
	test_basics<vector_block<uint64_t> >();
	test_basics<vector_malloc<uint64_t> >();
	test_basics<vector_malloc_counter_clear<uint64_t> >();
	test_basics<vector_realloc<uint64_t> >();
	test_basics<vector_realloc_counter_clear<uint64_t> >();
	test_basics<vector_realloc_shrink_clear<uint64_t> >();
	/*********************************************************/
	test_insertion_sort();
	/*********************************************************/
	test_routines();
	/*********************************************************/
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Steve Reinhardt
 */

/*
 * This code was originally written by Steve Reinhardt as part of
 * the Wisconsin Wind Tunnel simulator.  Relicensed as part of M5
 * by permission.
 */

#ifndef NO_FAST_ALLOC

#ifdef __GNUC__
#pragma implementation
#endif

#include <assert.h>
#include "base/fast_alloc.hh"

void *FastAlloc::freeLists[Num_Buckets];

#ifdef FAST_ALLOC_STATS
unsigned FastAlloc::newCount[Num_Buckets];
unsigned FastAlloc::deleteCount[Num_Buckets];
unsigned FastAlloc::allocCount[Num_Buckets];
#endif

void *FastAlloc::moreStructs(int bucket)
{
    assert(bucket > 0 && bucket < Num_Buckets);

    int sz = bucket * Alloc_Quantum;
    const int nstructs = Num_Structs_Per_New;	// how many to allocate?
    char *p = ::new char[nstructs * sz];

#ifdef FAST_ALLOC_STATS
    ++allocCount[bucket];
#endif

    freeLists[bucket] = p;
    for (int i = 0; i < (nstructs-2); ++i, p += sz)
        *(void **)p = p + sz;
    *(void **)p = 0;

    return (p + sz);
}

#ifdef FAST_ALLOC_DEBUG

#include <typeinfo>
#include <iostream>
#include <iomanip>
#include <map>
#include <string>

using namespace std;

// count of in-use FastAlloc objects
int FastAlloc::numInUse;

// dummy head & tail object for doubly linked list of in-use FastAlloc
// objects
FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);

// special constructor for dummy head: make inUsePrev & inUseNext
// point to self
FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
{
    inUsePrev = prev;
    inUseNext = next;
}

// constructor: marks as in use, add to in-use list
FastAlloc::FastAlloc()
{
    // mark this object in use
    inUse = true;

    // update count
    ++numInUse;

    // add to tail of list of in-use objects ("before" dummy head)
    FastAlloc *myNext = &inUseHead;
    FastAlloc *myPrev = inUseHead.inUsePrev;

    inUsePrev = myPrev;
    inUseNext = myNext;
    myPrev->inUseNext = this;
    myNext->inUsePrev = this;
}

// destructor: mark not in use, remove from in-use list
FastAlloc::~FastAlloc()
{
    assert(inUse);
    inUse = false;

    --numInUse;
    assert(numInUse >= 0);

    // remove me from in-use list
    inUsePrev->inUseNext = inUseNext;
    inUseNext->inUsePrev = inUsePrev;
}

// summarize in-use list
void
FastAlloc::dump_summary()
{
    map<string, int> typemap;

    for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
    {
        ++typemap[typeid(*p).name()];
    }

    map<string, int>::const_iterator mapiter;

    cout << " count  type\n"
         << " -----  ----\n";
    for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
    {
        cout << setw(6) << mapiter->second << "  " << mapiter->first << endl;
    }
}

// show oldest n items on in-use list
void
FastAlloc::dump_oldest(int n)
{
    // sanity check: don't want to crash the debugger if you forget to
    // pass in a parameter
    if (n < 0 || n > numInUse)
    {
        cout << "FastAlloc::dump_oldest: bad arg " << n
             << " (" << numInUse << " objects in use" << endl;
        return;
    }

    for (FastAlloc *p = inUseHead.inUsePrev;
         p != &inUseHead && n > 0;
         p = p->inUsePrev, --n)
    {
        cout << p << " " << typeid(*p).name() << endl;
    }
}

//
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
fast_alloc_summary()
{
    FastAlloc::dump_summary();
}

fast_alloc_oldest(int n)
{
    FastAlloc::dump_oldest(n);
}

#endif

#endif // NO_FAST_ALLOC
<commit_msg>Make NO_FAST_ALLOC compile.<commit_after>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Steve Reinhardt
 */

/*
 * This code was originally written by Steve Reinhardt as part of
 * the Wisconsin Wind Tunnel simulator.  Relicensed as part of M5
 * by permission.
 */

#include <assert.h>
#include "base/fast_alloc.hh"

#if !NO_FAST_ALLOC

#ifdef __GNUC__
#pragma implementation
#endif

void *FastAlloc::freeLists[Num_Buckets];

#ifdef FAST_ALLOC_STATS
unsigned FastAlloc::newCount[Num_Buckets];
unsigned FastAlloc::deleteCount[Num_Buckets];
unsigned FastAlloc::allocCount[Num_Buckets];
#endif

void *FastAlloc::moreStructs(int bucket)
{
    assert(bucket > 0 && bucket < Num_Buckets);

    int sz = bucket * Alloc_Quantum;
    const int nstructs = Num_Structs_Per_New;	// how many to allocate?
    char *p = ::new char[nstructs * sz];

#ifdef FAST_ALLOC_STATS
    ++allocCount[bucket];
#endif

    freeLists[bucket] = p;
    for (int i = 0; i < (nstructs-2); ++i, p += sz)
        *(void **)p = p + sz;
    *(void **)p = 0;

    return (p + sz);
}

#ifdef FAST_ALLOC_DEBUG

#include <typeinfo>
#include <iostream>
#include <iomanip>
#include <map>
#include <string>

using namespace std;

// count of in-use FastAlloc objects
int FastAlloc::numInUse;

// dummy head & tail object for doubly linked list of in-use FastAlloc
// objects
FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);

// special constructor for dummy head: make inUsePrev & inUseNext
// point to self
FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
{
    inUsePrev = prev;
    inUseNext = next;
}

// constructor: marks as in use, add to in-use list
FastAlloc::FastAlloc()
{
    // mark this object in use
    inUse = true;

    // update count
    ++numInUse;

    // add to tail of list of in-use objects ("before" dummy head)
    FastAlloc *myNext = &inUseHead;
    FastAlloc *myPrev = inUseHead.inUsePrev;

    inUsePrev = myPrev;
    inUseNext = myNext;
    myPrev->inUseNext = this;
    myNext->inUsePrev = this;
}

// destructor: mark not in use, remove from in-use list
FastAlloc::~FastAlloc()
{
    assert(inUse);
    inUse = false;

    --numInUse;
    assert(numInUse >= 0);

    // remove me from in-use list
    inUsePrev->inUseNext = inUseNext;
    inUseNext->inUsePrev = inUsePrev;
}

// summarize in-use list
void
FastAlloc::dump_summary()
{
    map<string, int> typemap;

    for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
    {
        ++typemap[typeid(*p).name()];
    }

    map<string, int>::const_iterator mapiter;

    cout << " count  type\n"
         << " -----  ----\n";
    for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
    {
        cout << setw(6) << mapiter->second << "  " << mapiter->first << endl;
    }
}

// show oldest n items on in-use list
void
FastAlloc::dump_oldest(int n)
{
    // sanity check: don't want to crash the debugger if you forget to
    // pass in a parameter
    if (n < 0 || n > numInUse)
    {
        cout << "FastAlloc::dump_oldest: bad arg " << n
             << " (" << numInUse << " objects in use" << endl;
        return;
    }

    for (FastAlloc *p = inUseHead.inUsePrev;
         p != &inUseHead && n > 0;
         p = p->inUsePrev, --n)
    {
        cout << p << " " << typeid(*p).name() << endl;
    }
}

//
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
fast_alloc_summary()
{
    FastAlloc::dump_summary();
}

fast_alloc_oldest(int n)
{
    FastAlloc::dump_oldest(n);
}

#endif

#endif // NO_FAST_ALLOC
<|endoftext|>