<commit_before>#include "runner/at_handler.hh"

#include <iostream>
#include <list>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include "scheduler/tag.hh"

namespace runner
{

  class AtJob
  {
  public:
    AtJob(rObject condition, rObject clause, rObject on_leave,
	  scheduler::tags_type tags);
    bool blocked() const;
    bool frozen() const;
    const rObject& condition_get() const;
    const rObject& clause_get() const;
    const rObject& on_leave_get() const;
    bool triggered_get() const;
    void triggered_set(bool);
    const scheduler::tags_type& tags_get() const;
  private:
    rObject condition_;
    rObject clause_;
    rObject on_leave_;
    bool triggered_;
    scheduler::tags_type tags_;
  };

  class AtHandler : public Runner
  {
  public:
    AtHandler(const Runner&);
    virtual ~AtHandler();
    virtual void work();
    virtual bool frozen() const;
    virtual bool blocked() const;
    void add_job(AtJob*);
  private:
    void complete_tags(const AtJob&);
    void rebuild_tags();
    typedef boost::ptr_vector<AtJob> at_jobs_type;
    at_jobs_type jobs_;
    bool yielding;
    scheduler::tags_type tags_;
  };

  // There is only one at job handler. It will be created if it doesn't exist
  // and destroyed when it has no more jobs to handle.
  static AtHandler* at_job_handler;

  AtHandler::AtHandler(const Runner& model)
    : Runner(model, 0),
      yielding(false)
  {
  }

  AtHandler::~AtHandler()
  {
    jobs_.release();
  }

  void
  AtHandler::work()
  {
    bool check_for_blocked = true;
    bool tags_need_rebuilding = false;
    side_effect_free_set(true);

    while (true)
    {
      non_interruptible_set(true);
      yielding = false;

      // If we have to check for blocked jobs, do it at the beginning
      // to make sure we do not miss a "stop" because some condition
      // evaluation mistakenly reenters the scheduler. We know that we
      // have to check for blocked jobs because we have had an indication
      // that tags needed to be rebuilt.

      if (tags_need_rebuilding)
	jobs_.erase_if(boost::bind(&AtJob::blocked, _1));

      for (at_jobs_type::iterator job = jobs_.begin();
	   job != jobs_.end();
	   /* Do not increment as we will also use erase() to advance */)
      {
	// If job has been frozen, we will not consider it for the moment.
	if (job->frozen())
	{
	  ++job;
	  continue;
	}

	// Check the job condition and continue if it has not changed.
	bool new_state;
	try
	{
	  new_state =
	    object::is_true(urbi_call(*this, job->condition_get(), SYMBOL(eval)));
	}
	catch (const kernel::exception& ke)
	{
	  std::cerr << "at condition triggered an exception: " << ke.what()
		    << std::endl;
	  tags_need_rebuilding = true;
	  job = jobs_.erase(job);
	  continue;
	}
	catch (...)
	{
	  std::cerr << "at condition triggered an exception\n";
	  job = jobs_.erase(job);
	  continue;
	}
	if (new_state == job->triggered_get())
	{
	  ++job;
	  continue;
	}

	// There has been a change in the condition, act accordingly depending
	// on whether we have seen a rising or a falling edge and save the
	// condition evaluation result.
	const rObject& to_launch =
	  new_state ? job->clause_get() : job->on_leave_get();
	if (to_launch != object::nil_class)
	{
	  // Temporarily install the needed tags as the current tags.
	  tags_set(job->tags_get());

	  // We do not need to check for an exception here as "detach",
	  // which is the function being called, will not throw and any
	  // exception thrown in the detached runner will not be caught
	  // here anyway.
	  urbi_call(*this, to_launch, SYMBOL(eval));
	}
	job->triggered_set(new_state);
	++job;
      }

      // If we have no more jobs, we can destroy ourselves.
      if (jobs_.empty())
      {
	at_job_handler = 0;
	terminate_now();
      }

      non_interruptible_set(false);
      check_for_blocked = false;
      yielding = true;

      // Rebuild tags if our list of jobs has changed.
      if (tags_need_rebuilding)
	rebuild_tags();
      tags_need_rebuilding = false;

      // Go to sleep
      try
      {
	// We want to appear blocked only when explicitly yielding and
	// catching the exception. If, by mistake, a condition evaluation
	// yields and is blocked, we do not want it to get the bogus
        // exception.
	yield_until_things_changed();
      }
      catch (const scheduler::BlockedException& e)
      {
	// We have at least one "at" job which needs to be blocked.
	tags_need_rebuilding = true;
      }
      catch (const kernel::exception& e)
      {
	std::cerr << "at job handler exited with exception " << e.what()
		  << std::endl;
	throw;
      }
      catch (...)
      {
	std::cerr << "at job handler exited with unknown exception\n";
	throw;
      }
    }
  }

  bool
  AtHandler::frozen() const
  {
    return false;
  }

  bool
  AtHandler::blocked() const
  {
    if (!yielding)
      return false;
    foreach (const scheduler::rTag& t, tags_)
      if (t->blocked())
	return true;
    return false;
  }

  void
  AtHandler::add_job(AtJob* job)
  {
    jobs_.push_back(job);
    complete_tags(*job);
  }

  void
  AtHandler::rebuild_tags()
  {
    tags_.clear();
    foreach (const AtJob& job, jobs_)
      complete_tags(job);
  }

  void
  AtHandler::complete_tags(const AtJob& job)
  {
    foreach (scheduler::rTag t, job.tags_get())
    {
      foreach (const scheduler::rTag& u, tags_)
	if (t == u)
	  goto already_found;
      tags_.push_back(t);
    already_found:
      ;
    }
  }

  AtJob::AtJob(rObject condition, rObject clause, rObject on_leave,
	       scheduler::tags_type tags)
    : condition_(condition),
      clause_(clause),
      on_leave_(on_leave),
      triggered_(false),
      tags_(tags)
  {
  }

  bool
  AtJob::blocked() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->blocked())
	return true;
    return false;
  }

  bool
  AtJob::frozen() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->frozen())
	return true;
    return false;
  }

  const rObject&
  AtJob::condition_get() const
  {
    return condition_;
  }

  const rObject&
  AtJob::clause_get() const
  {
    return clause_;
  }

  const rObject&
  AtJob::on_leave_get() const
  {
    return on_leave_;
  }

  bool
  AtJob::triggered_get() const
  {
    return triggered_;
  }

  void
  AtJob::triggered_set(bool t)
  {
    triggered_ = t;
  }

  const scheduler::tags_type&
  AtJob::tags_get() const
  {
    return tags_;
  }

  void
  register_at_job(const runner::Runner& starter,
		  rObject condition,
		  rObject clause,
		  rObject on_leave)
  {
    if (!at_job_handler)
    {
      at_job_handler = new AtHandler(starter);
      at_job_handler->start_job();
    }
    AtJob* job = new AtJob(condition,
			   clause,
			   on_leave,
			   starter.tags_get());
    at_job_handler->add_job(job);
  }

} // namespace runner
<commit_msg>Use ptr_list instead of ptr_vector in at job handler.<commit_after>#include "runner/at_handler.hh"

#include <iostream>
#include <list>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_list.hpp>

#include "scheduler/tag.hh"

namespace runner
{

  class AtJob
  {
  public:
    AtJob(rObject condition, rObject clause, rObject on_leave,
	  scheduler::tags_type tags);
    bool blocked() const;
    bool frozen() const;
    const rObject& condition_get() const;
    const rObject& clause_get() const;
    const rObject& on_leave_get() const;
    bool triggered_get() const;
    void triggered_set(bool);
    const scheduler::tags_type& tags_get() const;
  private:
    rObject condition_;
    rObject clause_;
    rObject on_leave_;
    bool triggered_;
    scheduler::tags_type tags_;
  };

  class AtHandler : public Runner
  {
  public:
    AtHandler(const Runner&);
    virtual ~AtHandler();
    virtual void work();
    virtual bool frozen() const;
    virtual bool blocked() const;
    void add_job(AtJob*);
  private:
    void complete_tags(const AtJob&);
    void rebuild_tags();
    typedef boost::ptr_list<AtJob> at_jobs_type;
    at_jobs_type jobs_;
    bool yielding;
    scheduler::tags_type tags_;
  };

  // There is only one at job handler. It will be created if it doesn't exist
  // and destroyed when it has no more jobs to handle.
  static AtHandler* at_job_handler;

  AtHandler::AtHandler(const Runner& model)
    : Runner(model, 0),
      yielding(false)
  {
  }

  AtHandler::~AtHandler()
  {
    jobs_.release();
  }

  void
  AtHandler::work()
  {
    bool check_for_blocked = true;
    bool tags_need_rebuilding = false;
    side_effect_free_set(true);

    while (true)
    {
      non_interruptible_set(true);
      yielding = false;

      // If we have to check for blocked jobs, do it at the beginning
      // to make sure we do not miss a "stop" because some condition
      // evaluation mistakenly reenters the scheduler. We know that we
      // have to check for blocked jobs because we have had an indication
      // that tags needed to be rebuilt.

      if (tags_need_rebuilding)
	jobs_.erase_if(boost::bind(&AtJob::blocked, _1));

      for (at_jobs_type::iterator job = jobs_.begin();
	   job != jobs_.end();
	   /* Do not increment as we will also use erase() to advance */)
      {
	// If job has been frozen, we will not consider it for the moment.
	if (job->frozen())
	{
	  ++job;
	  continue;
	}

	// Check the job condition and continue if it has not changed.
	bool new_state;
	try
	{
	  new_state =
	    object::is_true(urbi_call(*this, job->condition_get(), SYMBOL(eval)));
	}
	catch (const kernel::exception& ke)
	{
	  std::cerr << "at condition triggered an exception: " << ke.what()
		    << std::endl;
	  tags_need_rebuilding = true;
	  job = jobs_.erase(job);
	  continue;
	}
	catch (...)
	{
	  std::cerr << "at condition triggered an exception\n";
	  job = jobs_.erase(job);
	  continue;
	}
	if (new_state == job->triggered_get())
	{
	  ++job;
	  continue;
	}

	// There has been a change in the condition, act accordingly depending
	// on whether we have seen a rising or a falling edge and save the
	// condition evaluation result.
	const rObject& to_launch =
	  new_state ? job->clause_get() : job->on_leave_get();
	if (to_launch != object::nil_class)
	{
	  // Temporarily install the needed tags as the current tags.
	  tags_set(job->tags_get());

	  // We do not need to check for an exception here as "detach",
	  // which is the function being called, will not throw and any
	  // exception thrown in the detached runner will not be caught
	  // here anyway.
	  urbi_call(*this, to_launch, SYMBOL(eval));
	}
	job->triggered_set(new_state);
	++job;
      }

      // If we have no more jobs, we can destroy ourselves.
      if (jobs_.empty())
      {
	at_job_handler = 0;
	terminate_now();
      }

      non_interruptible_set(false);
      check_for_blocked = false;
      yielding = true;

      // Rebuild tags if our list of jobs has changed.
      if (tags_need_rebuilding)
	rebuild_tags();
      tags_need_rebuilding = false;

      // Go to sleep
      try
      {
	// We want to appear blocked only when explicitly yielding and
	// catching the exception. If, by mistake, a condition evaluation
	// yields and is blocked, we do not want it to get the bogus
        // exception.
	yield_until_things_changed();
      }
      catch (const scheduler::BlockedException& e)
      {
	// We have at least one "at" job which needs to be blocked.
	tags_need_rebuilding = true;
      }
      catch (const kernel::exception& e)
      {
	std::cerr << "at job handler exited with exception " << e.what()
		  << std::endl;
	throw;
      }
      catch (...)
      {
	std::cerr << "at job handler exited with unknown exception\n";
	throw;
      }
    }
  }

  bool
  AtHandler::frozen() const
  {
    return false;
  }

  bool
  AtHandler::blocked() const
  {
    if (!yielding)
      return false;
    foreach (const scheduler::rTag& t, tags_)
      if (t->blocked())
	return true;
    return false;
  }

  void
  AtHandler::add_job(AtJob* job)
  {
    jobs_.push_back(job);
    complete_tags(*job);
  }

  void
  AtHandler::rebuild_tags()
  {
    tags_.clear();
    foreach (const AtJob& job, jobs_)
      complete_tags(job);
  }

  void
  AtHandler::complete_tags(const AtJob& job)
  {
    foreach (scheduler::rTag t, job.tags_get())
    {
      foreach (const scheduler::rTag& u, tags_)
	if (t == u)
	  goto already_found;
      tags_.push_back(t);
    already_found:
      ;
    }
  }

  AtJob::AtJob(rObject condition, rObject clause, rObject on_leave,
	       scheduler::tags_type tags)
    : condition_(condition),
      clause_(clause),
      on_leave_(on_leave),
      triggered_(false),
      tags_(tags)
  {
  }

  bool
  AtJob::blocked() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->blocked())
	return true;
    return false;
  }

  bool
  AtJob::frozen() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->frozen())
	return true;
    return false;
  }

  const rObject&
  AtJob::condition_get() const
  {
    return condition_;
  }

  const rObject&
  AtJob::clause_get() const
  {
    return clause_;
  }

  const rObject&
  AtJob::on_leave_get() const
  {
    return on_leave_;
  }

  bool
  AtJob::triggered_get() const
  {
    return triggered_;
  }

  void
  AtJob::triggered_set(bool t)
  {
    triggered_ = t;
  }

  const scheduler::tags_type&
  AtJob::tags_get() const
  {
    return tags_;
  }

  void
  register_at_job(const runner::Runner& starter,
		  rObject condition,
		  rObject clause,
		  rObject on_leave)
  {
    if (!at_job_handler)
    {
      at_job_handler = new AtHandler(starter);
      at_job_handler->start_job();
    }
    AtJob* job = new AtJob(condition,
			   clause,
			   on_leave,
			   starter.tags_get());
    at_job_handler->add_job(job);
  }

} // namespace runner
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>

#include "gflags/gflags.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_audio/channel_buffer.h"
#include "webrtc/common_audio/wav_file.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/audio_processing/test/audio_file_processor.h"
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
#include "webrtc/modules/audio_processing/test/test_utils.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/test/testsupport/trace_to_stderr.h"

DEFINE_string(dump, "", "Name of the aecdump debug file to read from.");
DEFINE_string(i, "", "Name of the capture input stream file to read from.");
DEFINE_string(
    o,
    "out.wav",
    "Name of the output file to write the processed capture stream to.");
DEFINE_int32(out_channels, 1, "Number of output channels.");
DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
DEFINE_string(mic_positions, "",
    "Space delimited cartesian coordinates of microphones in meters. "
    "The coordinates of each point are contiguous. "
    "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
DEFINE_double(
    target_angle_degrees,
    90,
    "The azimuth of the target in degrees. Only applies to beamforming.");

DEFINE_bool(aec, false, "Enable echo cancellation.");
DEFINE_bool(agc, false, "Enable automatic gain control.");
DEFINE_bool(hpf, false, "Enable high-pass filtering.");
DEFINE_bool(ns, false, "Enable noise suppression.");
DEFINE_bool(ts, false, "Enable transient suppression.");
DEFINE_bool(bf, false, "Enable beamforming.");
DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
DEFINE_bool(all, false, "Enable all components.");

DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");

DEFINE_bool(perf, false, "Enable performance tests.");

namespace webrtc {
namespace {

const int kChunksPerSecond = 100;
const char kUsage[] =
    "Command-line tool to run audio processing on WAV files. Accepts either\n"
    "an input capture WAV file or protobuf debug dump and writes to an output\n"
    "WAV file.\n"
    "\n"
    "All components are disabled by default. If any bi-directional components\n"
    "are enabled, only debug dump files are permitted.";

}  // namespace

int main(int argc, char* argv[]) {
  google::SetUsageMessage(kUsage);
  google::ParseCommandLineFlags(&argc, &argv, true);

  if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
    fprintf(stderr,
            "An input file must be specified with either -i or -dump.\n");
    return 1;
  }
  if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) {
    fprintf(stderr, "-aec and -ie require a -dump file.\n");
    return 1;
  }
  if (FLAGS_ie) {
    fprintf(stderr,
            "FIXME(ajm): The intelligibility enhancer output is not dumped.\n");
    return 1;
  }

  test::TraceToStderr trace_to_stderr(true);
  Config config;
  if (FLAGS_bf || FLAGS_all) {
    if (FLAGS_mic_positions.empty()) {
      fprintf(stderr, "-mic_positions must be specified when -bf is used.\n");
      return 1;
    }
    config.Set<Beamforming>(new Beamforming(
        true, ParseArrayGeometry(FLAGS_mic_positions),
        SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f,
                        1.f)));
  }
  config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
  config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all));

  rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
  RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
  if (FLAGS_ns_level != -1) {
    RTC_CHECK_EQ(kNoErr,
                 ap->noise_suppression()->set_level(
                     static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
  }

  rtc::scoped_ptr<AudioFileProcessor> processor;
  auto out_file = rtc_make_scoped_ptr(
      new WavWriter(FLAGS_o, FLAGS_out_sample_rate, FLAGS_out_channels));
  std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl;
  if (FLAGS_dump.empty()) {
    auto in_file = rtc_make_scoped_ptr(new WavReader(FLAGS_i));
    std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl;
    processor.reset(
        new WavFileProcessor(ap.Pass(), in_file.Pass(), out_file.Pass()));

  } else {
    processor.reset(new AecDumpFileProcessor(
        ap.Pass(), fopen(FLAGS_dump.c_str(), "rb"), out_file.Pass()));
  }

  int num_chunks = 0;
  while (processor->ProcessChunk()) {
    trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
    ++num_chunks;
  }

  if (FLAGS_perf) {
    const auto& proc_time = processor->proc_time();
    int64_t exec_time_us = proc_time.sum.Microseconds();
    printf(
        "\nExecution time: %.3f s, File time: %.2f s\n"
        "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
        exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
        exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
        1.f * proc_time.min.Microseconds());
  }

  return 0;
}

}  // namespace webrtc

int main(int argc, char* argv[]) {
  return webrtc::main(argc, argv);
}
<commit_msg>Fix TransientSuppression in audioproc_float<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>

#include "gflags/gflags.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_audio/channel_buffer.h"
#include "webrtc/common_audio/wav_file.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/audio_processing/test/audio_file_processor.h"
#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
#include "webrtc/modules/audio_processing/test/test_utils.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/test/testsupport/trace_to_stderr.h"

DEFINE_string(dump, "", "Name of the aecdump debug file to read from.");
DEFINE_string(i, "", "Name of the capture input stream file to read from.");
DEFINE_string(
    o,
    "out.wav",
    "Name of the output file to write the processed capture stream to.");
DEFINE_int32(out_channels, 1, "Number of output channels.");
DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
DEFINE_string(mic_positions, "",
    "Space delimited cartesian coordinates of microphones in meters. "
    "The coordinates of each point are contiguous. "
    "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
DEFINE_double(
    target_angle_degrees,
    90,
    "The azimuth of the target in degrees. Only applies to beamforming.");

DEFINE_bool(aec, false, "Enable echo cancellation.");
DEFINE_bool(agc, false, "Enable automatic gain control.");
DEFINE_bool(hpf, false, "Enable high-pass filtering.");
DEFINE_bool(ns, false, "Enable noise suppression.");
DEFINE_bool(ts, false, "Enable transient suppression.");
DEFINE_bool(bf, false, "Enable beamforming.");
DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
DEFINE_bool(all, false, "Enable all components.");

DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");

DEFINE_bool(perf, false, "Enable performance tests.");

namespace webrtc {
namespace {

const int kChunksPerSecond = 100;
const char kUsage[] =
    "Command-line tool to run audio processing on WAV files. Accepts either\n"
    "an input capture WAV file or protobuf debug dump and writes to an output\n"
    "WAV file.\n"
    "\n"
    "All components are disabled by default. If any bi-directional components\n"
    "are enabled, only debug dump files are permitted.";

}  // namespace

int main(int argc, char* argv[]) {
  google::SetUsageMessage(kUsage);
  google::ParseCommandLineFlags(&argc, &argv, true);

  if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
    fprintf(stderr,
            "An input file must be specified with either -i or -dump.\n");
    return 1;
  }
  if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) {
    fprintf(stderr, "-aec and -ie require a -dump file.\n");
    return 1;
  }
  if (FLAGS_ie) {
    fprintf(stderr,
            "FIXME(ajm): The intelligibility enhancer output is not dumped.\n");
    return 1;
  }

  test::TraceToStderr trace_to_stderr(true);
  Config config;
  if (FLAGS_bf || FLAGS_all) {
    if (FLAGS_mic_positions.empty()) {
      fprintf(stderr, "-mic_positions must be specified when -bf is used.\n");
      return 1;
    }
    config.Set<Beamforming>(new Beamforming(
        true, ParseArrayGeometry(FLAGS_mic_positions),
        SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f,
                        1.f)));
  }
  config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
  config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all));

  rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
  RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
  RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
  if (FLAGS_ns_level != -1) {
    RTC_CHECK_EQ(kNoErr,
                 ap->noise_suppression()->set_level(
                     static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
  }
  ap->set_stream_key_pressed(FLAGS_ts);

  rtc::scoped_ptr<AudioFileProcessor> processor;
  auto out_file = rtc_make_scoped_ptr(
      new WavWriter(FLAGS_o, FLAGS_out_sample_rate, FLAGS_out_channels));
  std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl;
  if (FLAGS_dump.empty()) {
    auto in_file = rtc_make_scoped_ptr(new WavReader(FLAGS_i));
    std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl;
    processor.reset(
        new WavFileProcessor(ap.Pass(), in_file.Pass(), out_file.Pass()));

  } else {
    processor.reset(new AecDumpFileProcessor(
        ap.Pass(), fopen(FLAGS_dump.c_str(), "rb"), out_file.Pass()));
  }

  int num_chunks = 0;
  while (processor->ProcessChunk()) {
    trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
    ++num_chunks;
  }

  if (FLAGS_perf) {
    const auto& proc_time = processor->proc_time();
    int64_t exec_time_us = proc_time.sum.Microseconds();
    printf(
        "\nExecution time: %.3f s, File time: %.2f s\n"
        "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
        exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
        exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
        1.f * proc_time.min.Microseconds());
  }

  return 0;
}

}  // namespace webrtc

int main(int argc, char* argv[]) {
  return webrtc::main(argc, argv);
}
<|endoftext|>


<commit_before><commit_msg>ATO-452 use scaled croorection AliTPCReconstructor::GetRecoParam()->GetCrosstalkCorrection()<commit_after><|endoftext|>


<commit_before>#include "TClass.h"
#include "TMethod.h"
#include "TMethodCall.h"
#include "TMethodArg.h"
#include "TFile.h"
#include "TList.h"
#include "TObjArray.h"
#include "TDirectory.h"
#include "TTreeStream.h"

#include "AliLog.h"
#include "AliAnalysisTask.h"

#include "AliTRDrecoTask.h"

ClassImp(AliTRDrecoTask)

//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask(const char *name, const char *title)
  : AliAnalysisTask(name, title)
  ,fNRefFigures(0)
  ,fDebugLevel(0)
  ,fPlotFuncList(0x0)
  ,fContainer(0x0)
  ,fTracks(0x0)
  ,fTrack(0x0)
  ,fMC(0x0)
  ,fESD(0x0)
  ,fDebugStream(0x0)
{
  DefineInput(0, TObjArray::Class());
  DefineOutput(0, TObjArray::Class());
}

//_______________________________________________________
AliTRDrecoTask::~AliTRDrecoTask()
{
  if(fDebugStream){
    delete fDebugStream;
    fDebugStream = 0x0;
  }

  if(fPlotFuncList){
    fPlotFuncList->Delete();
    delete fPlotFuncList;
    fPlotFuncList = 0x0;
  }

  if(fContainer){
    //fContainer->Delete();
    delete fContainer;
    fContainer = 0x0;
  }
}

//_______________________________________________________
void AliTRDrecoTask::ConnectInputData(Option_t *)
{
  //
  // Connect input data
  //

  fTracks = dynamic_cast<TObjArray *>(GetInputData(0));
}

//_______________________________________________________
void AliTRDrecoTask::Exec(Option_t *)
{
  if(!fPlotFuncList){
    AliWarning("No functor list defined for the reference plots");
    return;
  }
  if(!fTracks) return;
  if(!fTracks->GetEntriesFast()) return;

  AliTRDtrackInfo *trackInfo = 0x0;
  TIter plotIter(fPlotFuncList);
  TObjArrayIter trackIter(fTracks);
  while((trackInfo = dynamic_cast<AliTRDtrackInfo*>(trackIter()))){
    fTrack = trackInfo->GetTrack();
    fMC    = trackInfo->GetMCinfo();
    fESD   = trackInfo->GetESDinfo();

    TMethodCall *plot = 0x0;
    plotIter.Reset();
    while((plot=dynamic_cast<TMethodCall*>(plotIter()))){
      plot->Execute(this);
    }
  }
  PostData(0, fContainer);
}

//_______________________________________________________
void AliTRDrecoTask::GetRefFigure(Int_t /*ifig*/)
{
  AliWarning("Retrieving reference figures not implemented.");
}

//_______________________________________________________
void AliTRDrecoTask::InitFunctorList()
{
  TClass *c = this->IsA();

  TMethod *m = 0x0;
  TIter methIter(c->GetListOfMethods());
  while((m=dynamic_cast<TMethod*>(methIter()))){
    TString name(m->GetName());
    if(!name.BeginsWith("Plot")) continue;
    if(!fPlotFuncList) fPlotFuncList = new TList();
    fPlotFuncList->AddLast(new TMethodCall(c, (const char*)name, ""));
    printf("%s%s\n", m->GetName(), m->GetSignature());
  }
}

//_______________________________________________________
Bool_t AliTRDrecoTask::Load(const Char_t *filename)
{
  if(!TFile::Open(filename)) return kFALSE;
  TObjArray *o = (TObjArray*)gFile->Get(GetName());
  fContainer = (TObjArray*)o->Clone(GetName());
  gFile->Close();
  return kFALSE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PostProcess()
{
  AliWarning("Post processing of reference histograms not implemented.");
  return kFALSE;
}

//_______________________________________________________
void AliTRDrecoTask::SetDebugLevel(Int_t level)
{
  fDebugLevel = level;
  if(fDebugLevel>=1){
    TDirectory *savedir = gDirectory;
    fDebugStream = new TTreeSRedirector(Form("TRD.Debug%s.root", GetName()));
    savedir->cd();
  }
}
<commit_msg>less verbous<commit_after>#include "TClass.h"
#include "TMethod.h"
#include "TMethodCall.h"
#include "TMethodArg.h"
#include "TFile.h"
#include "TList.h"
#include "TObjArray.h"
#include "TDirectory.h"
#include "TTreeStream.h"

#include "AliLog.h"
#include "AliAnalysisTask.h"

#include "AliTRDrecoTask.h"

ClassImp(AliTRDrecoTask)

//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask(const char *name, const char *title)
  : AliAnalysisTask(name, title)
  ,fNRefFigures(0)
  ,fDebugLevel(0)
  ,fPlotFuncList(0x0)
  ,fContainer(0x0)
  ,fTracks(0x0)
  ,fTrack(0x0)
  ,fMC(0x0)
  ,fESD(0x0)
  ,fDebugStream(0x0)
{
  DefineInput(0, TObjArray::Class());
  DefineOutput(0, TObjArray::Class());
}

//_______________________________________________________
AliTRDrecoTask::~AliTRDrecoTask()
{
  if(fDebugStream){
    delete fDebugStream;
    fDebugStream = 0x0;
  }

  if(fPlotFuncList){
    fPlotFuncList->Delete();
    delete fPlotFuncList;
    fPlotFuncList = 0x0;
  }

  if(fContainer){
    //fContainer->Delete();
    delete fContainer;
    fContainer = 0x0;
  }
}

//_______________________________________________________
void AliTRDrecoTask::ConnectInputData(Option_t *)
{
  //
  // Connect input data
  //

  fTracks = dynamic_cast<TObjArray *>(GetInputData(0));
}

//_______________________________________________________
void AliTRDrecoTask::Exec(Option_t *)
{
  if(!fPlotFuncList){
    AliWarning("No functor list defined for the reference plots");
    return;
  }
  if(!fTracks) return;
  if(!fTracks->GetEntriesFast()) return;

  AliTRDtrackInfo *trackInfo = 0x0;
  TIter plotIter(fPlotFuncList);
  TObjArrayIter trackIter(fTracks);
  while((trackInfo = dynamic_cast<AliTRDtrackInfo*>(trackIter()))){
    fTrack = trackInfo->GetTrack();
    fMC    = trackInfo->GetMCinfo();
    fESD   = trackInfo->GetESDinfo();

    TMethodCall *plot = 0x0;
    plotIter.Reset();
    while((plot=dynamic_cast<TMethodCall*>(plotIter()))){
      plot->Execute(this);
    }
  }
  PostData(0, fContainer);
}

//_______________________________________________________
void AliTRDrecoTask::GetRefFigure(Int_t /*ifig*/)
{
  AliWarning("Retrieving reference figures not implemented.");
}

//_______________________________________________________
void AliTRDrecoTask::InitFunctorList()
{
  TClass *c = this->IsA();

  TMethod *m = 0x0;
  TIter methIter(c->GetListOfMethods());
  while((m=dynamic_cast<TMethod*>(methIter()))){
    TString name(m->GetName());
    if(!name.BeginsWith("Plot")) continue;
    if(!fPlotFuncList) fPlotFuncList = new TList();
    fPlotFuncList->AddLast(new TMethodCall(c, (const char*)name, ""));
    //printf("%s%s\n", m->GetName(), m->GetSignature());
  }
}

//_______________________________________________________
Bool_t AliTRDrecoTask::Load(const Char_t *filename)
{
  if(!TFile::Open(filename)) return kFALSE;
  TObjArray *o = (TObjArray*)gFile->Get(GetName());
  fContainer = (TObjArray*)o->Clone(GetName());
  gFile->Close();
  return kFALSE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PostProcess()
{
  AliWarning("Post processing of reference histograms not implemented.");
  return kFALSE;
}

//_______________________________________________________
void AliTRDrecoTask::SetDebugLevel(Int_t level)
{
  fDebugLevel = level;
  if(fDebugLevel>=1){
    TDirectory *savedir = gDirectory;
    fDebugStream = new TTreeSRedirector(Form("TRD.Debug%s.root", GetName()));
    savedir->cd();
  }
}
<|endoftext|>


<commit_before>#include <thread>
#include <chrono>
#include <iostream>

#include "file_listener.hpp"

namespace fs = std::experimental::filesystem;

namespace amer {
    void file_listener::run() {
	m_listener_thread = std::thread{[this] { this->do_run(); }};
    }

    void file_listener::do_run() {
	while (true) {
	    for (auto&& f : fs::recursive_directory_iterator(m_config.get_source_dir()/"content")) {
		try {
		    auto new_write_time = fs::last_write_time(f);
		    if (!m_mod_times.count(f) || new_write_time != m_mod_times[f]) {
			m_mod_times[f] = new_write_time;
                        m_renderer.render_content(f);
			m_server.refresh();
		    }
		} catch(...) {}
	    }
	    std::this_thread::sleep_for(std::chrono::seconds(1));
	}
    }
}
<commit_msg>Poll for file changes every 100 microseconds instead of every second<commit_after>#include <thread>
#include <chrono>
#include <iostream>

#include "file_listener.hpp"

namespace fs = std::experimental::filesystem;

namespace amer {
    void file_listener::run() {
	m_listener_thread = std::thread{[this] { this->do_run(); }};
    }

    void file_listener::do_run() {
	while (true) {
	    for (auto&& f : fs::recursive_directory_iterator(m_config.get_source_dir()/"content")) {
		try {
		    auto new_write_time = fs::last_write_time(f);
		    if (!m_mod_times.count(f) || new_write_time != m_mod_times[f]) {
			m_mod_times[f] = new_write_time;
                        m_renderer.render_content(f);
			m_server.refresh();
		    }
		} catch(...) {}
	    }
	    std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
    }
}
<|endoftext|>


<commit_before>/*
  MusicXML Library
  Copyright (C) Grame 2006-2013

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Grame Research Laboratory, 11, cours de Verdun Gensoul 69002 Lyon - France
  research@grame.fr
*/

#include <iostream>
#include "xmlfile.h"
#include "xmlvisitor.h"
#include "tree_browser.h"

using namespace std;
using namespace MusicXML2;
namespace MusicXML2
{

//______________________________________________________________________________
SXMLFile TXMLFile::create ()  { TXMLFile* o = new TXMLFile; assert(o!=0); return o; }

//______________________________________________________________________________
TDocType::TDocType (const string start) : fStartElement(start), fPublic(true)
{
	fPubLitteral = "-//Recordare//DTD MusicXML 2.0 Partwise//EN";
	if (start == "score-partwise") {
		fSysLitteral = "http://www.musicxml.org/dtds/partwise.dtd";
	}
	else if (start == "score-timewise") {
		fSysLitteral = "http://www.musicxml.org/dtds/timewise.dtd";
	}
}

//______________________________________________________________________________
void TDocType::print (ostream& s)
{
	s	<< endl << "<!DOCTYPE " << fStartElement
		<< (fPublic ? " PUBLIC " : " SYSTEM ")
		<< "\"" << fPubLitteral << "\"\n\t\t\t\""
		<< fSysLitteral << "\">";
}

//______________________________________________________________________________
void TXMLDecl::print (ostream& s)
{
	s	<< "<?xml version=\"" << fVersion << "\"";
	if (!fEncoding.empty())			s << " encoding=\"" << fEncoding  << "\"";
	if (fStandalone != kundefined)	s << " standalone=\"" << (fStandalone ? "yes" : "no") << "\"";
	s << "?>";
}

//______________________________________________________________________________
void TXMLFile::print (ostream& stream)
{
	if (fXMLDecl) fXMLDecl->print(stream);
	if (fDocType) fDocType->print(stream);
	xmlvisitor v(stream);
	tree_browser<xmlelement> browser(&v);
	browser.browse(*elements());
}

}
<commit_msg>musicxml header version is now 3.1<commit_after>/*
  MusicXML Library
  Copyright (C) Grame 2006-2013

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.

  Grame Research Laboratory, 11, cours de Verdun Gensoul 69002 Lyon - France
  research@grame.fr
*/

#include <iostream>
#include "xmlfile.h"
#include "xmlvisitor.h"
#include "tree_browser.h"

using namespace std;
using namespace MusicXML2;
namespace MusicXML2
{

//______________________________________________________________________________
SXMLFile TXMLFile::create ()  { TXMLFile* o = new TXMLFile; assert(o!=0); return o; }

//______________________________________________________________________________
TDocType::TDocType (const string start) : fStartElement(start), fPublic(true)
{
	fPubLitteral = "-//Recordare//DTD MusicXML 3.1 Partwise//EN";
	if (start == "score-partwise") {
		fSysLitteral = "http://www.musicxml.org/dtds/partwise.dtd";
	}
	else if (start == "score-timewise") {
		fSysLitteral = "http://www.musicxml.org/dtds/timewise.dtd";
	}
}

//______________________________________________________________________________
void TDocType::print (ostream& s)
{
	s	<< endl << "<!DOCTYPE " << fStartElement
		<< (fPublic ? " PUBLIC " : " SYSTEM ")
		<< "\"" << fPubLitteral << "\"\n\t\t\t\""
		<< fSysLitteral << "\">";
}

//______________________________________________________________________________
void TXMLDecl::print (ostream& s)
{
	s	<< "<?xml version=\"" << fVersion << "\"";
	if (!fEncoding.empty())			s << " encoding=\"" << fEncoding  << "\"";
	if (fStandalone != kundefined)	s << " standalone=\"" << (fStandalone ? "yes" : "no") << "\"";
	s << "?>";
}

//______________________________________________________________________________
void TXMLFile::print (ostream& stream)
{
	if (fXMLDecl) fXMLDecl->print(stream);
	if (fDocType) fDocType->print(stream);
	xmlvisitor v(stream);
	tree_browser<xmlelement> browser(&v);
	browser.browse(*elements());
}

}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file ir_function_inlining.cpp
 *
 * Replaces calls to functions with the body of the function.
 */

#define NULL 0
#include "ir.h"
#include "ir_visitor.h"
#include "ir_function_inlining.h"
#include "glsl_types.h"

class variable_remap : public exec_node {
public:
   variable_remap(const ir_variable *old_var, ir_variable *new_var)
      : old_var(old_var), new_var(new_var)
   {
      /* empty */
   }
   const ir_variable *old_var;
   ir_variable *new_var;
};

class ir_function_cloning_visitor : public ir_visitor {
public:
   ir_function_cloning_visitor(ir_variable *retval)
      : retval(retval)
   {
      /* empty */
   }

   virtual ~ir_function_cloning_visitor()
   {
      /* empty */
   }

   void remap_variable(const ir_variable *old_var, ir_variable *new_var) {
      variable_remap *remap = new variable_remap(old_var, new_var);
      this->remap_list.push_tail(remap);
   }

   ir_variable *get_remapped_variable(ir_variable *var) {
      foreach_iter(exec_list_iterator, iter, this->remap_list) {
	 variable_remap *remap = (variable_remap *)iter.get();

	 if (var == remap->old_var)
	    return remap->new_var;
      }

      /* Not a reapped variable, so a global scoped reference, for example. */
      return var;
   }

   /* List of variable_remap for mapping from original function body variables
    * to inlined function body variables.
    */
   exec_list remap_list;

   /* Return value for the inlined function. */
   ir_variable *retval;

   /**
    * \name Visit methods
    *
    * As typical for the visitor pattern, there must be one \c visit method for
    * each concrete subclass of \c ir_instruction.  Virtual base classes within
    * the hierarchy should not have \c visit methods.
    */
   /*@{*/
   virtual void visit(ir_variable *);
   virtual void visit(ir_label *);
   virtual void visit(ir_loop *);
   virtual void visit(ir_loop_jump *);
   virtual void visit(ir_function_signature *);
   virtual void visit(ir_function *);
   virtual void visit(ir_expression *);
   virtual void visit(ir_swizzle *);
   virtual void visit(ir_dereference *);
   virtual void visit(ir_assignment *);
   virtual void visit(ir_constant *);
   virtual void visit(ir_call *);
   virtual void visit(ir_return *);
   virtual void visit(ir_if *);
   /*@}*/

   ir_instruction *result;
};

void
ir_function_cloning_visitor::visit(ir_variable *ir)
{
   ir_variable *new_var = ir->clone();

   this->result = new_var;

   this->remap_variable(ir, new_var);
}

void
ir_function_cloning_visitor::visit(ir_label *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_loop *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_function_signature *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_function *ir)
{
   (void) ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_expression *ir)
{
   unsigned int operand;
   ir_rvalue *op[2] = {NULL, NULL};

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      ir->operands[operand]->accept(this);
      op[operand] = this->result->as_rvalue();
      assert(op[operand]);
   }

   this->result = new ir_expression(ir->operation, ir->type, op[0], op[1]);
}

void
ir_function_cloning_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);

   this->result = new ir_swizzle(this->result->as_rvalue(), ir->mask);
}

void
ir_function_cloning_visitor::visit(ir_dereference *ir)
{
   if (ir->mode == ir_dereference::ir_reference_variable) {
      ir_variable *old_var = ir->var->as_variable();

      /* If it's a deref of a real variable, then we need to remap it if
       * it was local to the function.
       */
      if (old_var) {
	 ir_variable *new_var;

	 new_var = this->get_remapped_variable(old_var);

	 this->result = new ir_dereference(new_var);
      } else {
	 ir->var->accept(this);

	 this->result = new ir_dereference(this->result);
      }
   } else {
      this->result = NULL;
   }
}

void
ir_function_cloning_visitor::visit(ir_assignment *ir)
{
   ir_rvalue *lhs, *rhs, *condition;

   ir->lhs->accept(this);
   lhs = this->result->as_rvalue();

   ir->rhs->accept(this);
   rhs = this->result->as_rvalue();

   ir->condition->accept(this);
   condition = this->result->as_rvalue();

   this->result = new ir_assignment(lhs, rhs, condition);
}

void
ir_function_cloning_visitor::visit(ir_constant *ir)
{
   this->result = ir->clone();
}

void
ir_function_cloning_visitor::visit(ir_call *ir)
{
   exec_list parameters;

   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();

      param->accept(this);
      parameters.push_tail(this->result);
   }

   this->result = new ir_call(ir->get_callee(), &parameters);
}

void
ir_function_cloning_visitor::visit(ir_return *ir)
{
   ir_rvalue *rval;

   assert(this->retval);

   rval = ir->get_value();
   rval->accept(this);
   rval = this->result->as_rvalue();
   assert(rval);

   result = new ir_assignment(new ir_dereference(this->retval),
			      ir->get_value(), NULL);
}

void
ir_function_cloning_visitor::visit(ir_if *ir)
{
   (void) ir;
   result = NULL;
}

bool
can_inline(ir_call *call)
{
   bool found_return = false;

   /* FINISHME: Right now we only allow a single statement that is a return.
    */
   foreach_iter(exec_list_iterator, iter, call->get_callee()->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      if (ir->get_next()->get_next() != NULL)
	 return false;

      if (!ir->as_return())
	 return false;

      found_return = true;
   }

   return found_return;
}

bool
do_function_inlining(exec_list *instructions)
{
   bool progress;

   foreach_iter(exec_list_iterator, iter, *instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      ir_assignment *assign = ir->as_assignment();
      ir_call *call;

      if (assign) {
	 call = assign->rhs->as_call();
	 if (!call || !can_inline(call))
	    continue;

	 /* generates the parameter setup, function body, and returns the return
	  * value of the function
	  */
	 ir_rvalue *rhs = call->generate_inline(ir);
	 assert(rhs);

	 assign->rhs = rhs;
	 progress = true;
      } else if ((call = ir->as_call()) && can_inline(call)) {
	 (void)call->generate_inline(ir);
	 ir->remove();
	 progress = true;
      } else {
	 ir_function_inlining_visitor v;
	 ir->accept(&v);
      }
   }

   return progress;
}

ir_rvalue *
ir_call::generate_inline(ir_instruction *next_ir)
{
   ir_variable **parameters;
   int num_parameters;
   int i;
   ir_variable *retval = NULL;

   num_parameters = 0;
   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
      num_parameters++;

   parameters = new ir_variable *[num_parameters];

   /* Generate storage for the return value. */
   if (this->callee->return_type) {
      retval = new ir_variable(this->callee->return_type, "__retval");
      next_ir->insert_before(retval);
   }

   ir_function_cloning_visitor v = ir_function_cloning_visitor(retval);

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
   exec_list_iterator param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
      ir_rvalue *param = (ir_rvalue *) param_iter.get();

      /* Generate a new variable for the parameter. */
      parameters[i] = sig_param->clone();
      next_ir->insert_before(parameters[i]);

      v.remap_variable(sig_param, parameters[i]);

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i]->mode == ir_var_in ||
	  parameters[i]->mode == ir_var_inout) {
	 ir_assignment *assign;

	 assign = new ir_assignment(new ir_dereference(parameters[i]),
				    param, NULL);
	 next_ir->insert_before(assign);
      }

      sig_param_iter.next();
      param_iter.next();
   }

   /* Generate the inlined body of the function. */
   foreach_iter(exec_list_iterator, iter, callee->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();

      ir->accept(&v);
      assert(v.result);
      next_ir->insert_before(v.result);
   }

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i]->mode == ir_var_out ||
	  parameters[i]->mode == ir_var_inout) {
	 ir_assignment *assign;

	 assign = new ir_assignment(param->as_rvalue(),
				    new ir_dereference(parameters[i]),
				    NULL);
	 next_ir->insert_before(assign);
      }

      param_iter.next();
   }

   delete(parameters);

   if (retval)
      return new ir_dereference(retval);
   else
      return NULL;
}

void
ir_function_inlining_visitor::visit(ir_variable *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_label *ir)
{
   ir->signature->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_loop *ir)
{
   do_function_inlining(&ir->body_instructions);
}

void
ir_function_inlining_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_function_signature *ir)
{
   do_function_inlining(&ir->body);
}

void
ir_function_inlining_visitor::visit(ir_function *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_expression *ir)
{
   unsigned int operand;

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      ir->operands[operand]->accept(this);
   }
}

void
ir_function_inlining_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_dereference *ir)
{
   if (ir->mode == ir_dereference::ir_reference_array) {
      ir->selector.array_index->accept(this);
   }
   ir->var->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_assignment *ir)
{
   ir->rhs->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_constant *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_call *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_return *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_if *ir)
{
   ir->condition->accept(this);

   do_function_inlining(&ir->then_instructions);
   do_function_inlining(&ir->else_instructions);
}
<commit_msg>Add inlining support for array dereferences.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

/**
 * \file ir_function_inlining.cpp
 *
 * Replaces calls to functions with the body of the function.
 */

#define NULL 0
#include "ir.h"
#include "ir_visitor.h"
#include "ir_function_inlining.h"
#include "glsl_types.h"

class variable_remap : public exec_node {
public:
   variable_remap(const ir_variable *old_var, ir_variable *new_var)
      : old_var(old_var), new_var(new_var)
   {
      /* empty */
   }
   const ir_variable *old_var;
   ir_variable *new_var;
};

class ir_function_cloning_visitor : public ir_visitor {
public:
   ir_function_cloning_visitor(ir_variable *retval)
      : retval(retval)
   {
      /* empty */
   }

   virtual ~ir_function_cloning_visitor()
   {
      /* empty */
   }

   void remap_variable(const ir_variable *old_var, ir_variable *new_var) {
      variable_remap *remap = new variable_remap(old_var, new_var);
      this->remap_list.push_tail(remap);
   }

   ir_variable *get_remapped_variable(ir_variable *var) {
      foreach_iter(exec_list_iterator, iter, this->remap_list) {
	 variable_remap *remap = (variable_remap *)iter.get();

	 if (var == remap->old_var)
	    return remap->new_var;
      }

      /* Not a reapped variable, so a global scoped reference, for example. */
      return var;
   }

   /* List of variable_remap for mapping from original function body variables
    * to inlined function body variables.
    */
   exec_list remap_list;

   /* Return value for the inlined function. */
   ir_variable *retval;

   /**
    * \name Visit methods
    *
    * As typical for the visitor pattern, there must be one \c visit method for
    * each concrete subclass of \c ir_instruction.  Virtual base classes within
    * the hierarchy should not have \c visit methods.
    */
   /*@{*/
   virtual void visit(ir_variable *);
   virtual void visit(ir_label *);
   virtual void visit(ir_loop *);
   virtual void visit(ir_loop_jump *);
   virtual void visit(ir_function_signature *);
   virtual void visit(ir_function *);
   virtual void visit(ir_expression *);
   virtual void visit(ir_swizzle *);
   virtual void visit(ir_dereference *);
   virtual void visit(ir_assignment *);
   virtual void visit(ir_constant *);
   virtual void visit(ir_call *);
   virtual void visit(ir_return *);
   virtual void visit(ir_if *);
   /*@}*/

   ir_instruction *result;
};

void
ir_function_cloning_visitor::visit(ir_variable *ir)
{
   ir_variable *new_var = ir->clone();

   this->result = new_var;

   this->remap_variable(ir, new_var);
}

void
ir_function_cloning_visitor::visit(ir_label *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_loop *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_function_signature *ir)
{
   (void)ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_function *ir)
{
   (void) ir;
   this->result = NULL;
}

void
ir_function_cloning_visitor::visit(ir_expression *ir)
{
   unsigned int operand;
   ir_rvalue *op[2] = {NULL, NULL};

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      ir->operands[operand]->accept(this);
      op[operand] = this->result->as_rvalue();
      assert(op[operand]);
   }

   this->result = new ir_expression(ir->operation, ir->type, op[0], op[1]);
}

void
ir_function_cloning_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);

   this->result = new ir_swizzle(this->result->as_rvalue(), ir->mask);
}

void
ir_function_cloning_visitor::visit(ir_dereference *ir)
{
   if (ir->mode == ir_dereference::ir_reference_variable) {
      ir_variable *old_var = ir->var->as_variable();

      /* If it's a deref of a real variable, then we need to remap it if
       * it was local to the function.
       */
      if (old_var) {
	 ir_variable *new_var;

	 new_var = this->get_remapped_variable(old_var);

	 this->result = new ir_dereference(new_var);
      } else {
	 ir->var->accept(this);

	 this->result = new ir_dereference(this->result);
      }
   } else if (ir->mode == ir_dereference::ir_reference_array) {
      ir_instruction *variable;
      ir_rvalue *index;

      ir->var->accept(this);
      variable = this->result;

      ir->selector.array_index->accept(this);
      index = this->result->as_rvalue();

      this->result = new ir_dereference(variable, index);
   } else {
      assert(ir->mode == ir_dereference::ir_reference_record);
      /* FINISHME: inlining of structure references */
      assert(0);
   }
}

void
ir_function_cloning_visitor::visit(ir_assignment *ir)
{
   ir_rvalue *lhs, *rhs, *condition;

   ir->lhs->accept(this);
   lhs = this->result->as_rvalue();

   ir->rhs->accept(this);
   rhs = this->result->as_rvalue();

   ir->condition->accept(this);
   condition = this->result->as_rvalue();

   this->result = new ir_assignment(lhs, rhs, condition);
}

void
ir_function_cloning_visitor::visit(ir_constant *ir)
{
   this->result = ir->clone();
}

void
ir_function_cloning_visitor::visit(ir_call *ir)
{
   exec_list parameters;

   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *param = (ir_rvalue *)iter.get();

      param->accept(this);
      parameters.push_tail(this->result);
   }

   this->result = new ir_call(ir->get_callee(), &parameters);
}

void
ir_function_cloning_visitor::visit(ir_return *ir)
{
   ir_rvalue *rval;

   assert(this->retval);

   rval = ir->get_value();
   rval->accept(this);
   rval = this->result->as_rvalue();
   assert(rval);

   result = new ir_assignment(new ir_dereference(this->retval),
			      ir->get_value(), NULL);
}

void
ir_function_cloning_visitor::visit(ir_if *ir)
{
   (void) ir;
   result = NULL;
}

bool
can_inline(ir_call *call)
{
   bool found_return = false;

   /* FINISHME: Right now we only allow a single statement that is a return.
    */
   foreach_iter(exec_list_iterator, iter, call->get_callee()->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      if (ir->get_next()->get_next() != NULL)
	 return false;

      if (!ir->as_return())
	 return false;

      found_return = true;
   }

   return found_return;
}

bool
do_function_inlining(exec_list *instructions)
{
   bool progress;

   foreach_iter(exec_list_iterator, iter, *instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();
      ir_assignment *assign = ir->as_assignment();
      ir_call *call;

      if (assign) {
	 call = assign->rhs->as_call();
	 if (!call || !can_inline(call))
	    continue;

	 /* generates the parameter setup, function body, and returns the return
	  * value of the function
	  */
	 ir_rvalue *rhs = call->generate_inline(ir);
	 assert(rhs);

	 assign->rhs = rhs;
	 progress = true;
      } else if ((call = ir->as_call()) && can_inline(call)) {
	 (void)call->generate_inline(ir);
	 ir->remove();
	 progress = true;
      } else {
	 ir_function_inlining_visitor v;
	 ir->accept(&v);
      }
   }

   return progress;
}

ir_rvalue *
ir_call::generate_inline(ir_instruction *next_ir)
{
   ir_variable **parameters;
   int num_parameters;
   int i;
   ir_variable *retval = NULL;

   num_parameters = 0;
   foreach_iter(exec_list_iterator, iter_sig, this->callee->parameters)
      num_parameters++;

   parameters = new ir_variable *[num_parameters];

   /* Generate storage for the return value. */
   if (this->callee->return_type) {
      retval = new ir_variable(this->callee->return_type, "__retval");
      next_ir->insert_before(retval);
   }

   ir_function_cloning_visitor v = ir_function_cloning_visitor(retval);

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   exec_list_iterator sig_param_iter = this->callee->parameters.iterator();
   exec_list_iterator param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      const ir_variable *const sig_param = (ir_variable *) sig_param_iter.get();
      ir_rvalue *param = (ir_rvalue *) param_iter.get();

      /* Generate a new variable for the parameter. */
      parameters[i] = sig_param->clone();
      next_ir->insert_before(parameters[i]);

      v.remap_variable(sig_param, parameters[i]);

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i]->mode == ir_var_in ||
	  parameters[i]->mode == ir_var_inout) {
	 ir_assignment *assign;

	 assign = new ir_assignment(new ir_dereference(parameters[i]),
				    param, NULL);
	 next_ir->insert_before(assign);
      }

      sig_param_iter.next();
      param_iter.next();
   }

   /* Generate the inlined body of the function. */
   foreach_iter(exec_list_iterator, iter, callee->body) {
      ir_instruction *ir = (ir_instruction *)iter.get();

      ir->accept(&v);
      assert(v.result);
      next_ir->insert_before(v.result);
   }

   /* Generate the declarations for the parameters to our inlined code,
    * and set up the mapping of real function body variables to ours.
    */
   i = 0;
   param_iter = this->actual_parameters.iterator();
   for (i = 0; i < num_parameters; i++) {
      ir_instruction *const param = (ir_instruction *) param_iter.get();

      /* Move the actual param into our param variable if it's an 'in' type. */
      if (parameters[i]->mode == ir_var_out ||
	  parameters[i]->mode == ir_var_inout) {
	 ir_assignment *assign;

	 assign = new ir_assignment(param->as_rvalue(),
				    new ir_dereference(parameters[i]),
				    NULL);
	 next_ir->insert_before(assign);
      }

      param_iter.next();
   }

   delete(parameters);

   if (retval)
      return new ir_dereference(retval);
   else
      return NULL;
}

void
ir_function_inlining_visitor::visit(ir_variable *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_label *ir)
{
   ir->signature->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_loop *ir)
{
   do_function_inlining(&ir->body_instructions);
}

void
ir_function_inlining_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_function_signature *ir)
{
   do_function_inlining(&ir->body);
}

void
ir_function_inlining_visitor::visit(ir_function *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_expression *ir)
{
   unsigned int operand;

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      ir->operands[operand]->accept(this);
   }
}

void
ir_function_inlining_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_dereference *ir)
{
   if (ir->mode == ir_dereference::ir_reference_array) {
      ir->selector.array_index->accept(this);
   }
   ir->var->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_assignment *ir)
{
   ir->rhs->accept(this);
}

void
ir_function_inlining_visitor::visit(ir_constant *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_call *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_return *ir)
{
   (void) ir;
}

void
ir_function_inlining_visitor::visit(ir_if *ir)
{
   ir->condition->accept(this);

   do_function_inlining(&ir->then_instructions);
   do_function_inlining(&ir->else_instructions);
}
<|endoftext|>


<commit_before>#ifndef OBJECTS_H
#define OBJECTS_H

/*
Defines an Object::ref type, which is a tagged pointer type.
Usage:
	Object::ref x = Object::to_ref(1);//smallint
	Object::ref y = Object::to_ref(new(hp) Generic()); //object
	if(is_a<int>(x)) {
		std::cout << "x = " << as_a<int>(x) << std::endl;
	}
	if(is_a<Generic*>(y)) {
		std::cout << "y.field = " << as_a<Generic*>(y)->field
			<< std::endl;
	}
*/

#include<stdint.h>
#include<climits>

#include"unichars.hpp"

#ifdef MY_COMPILER
// without these my compiler signals an error -- stefano
// I suggest you try it now with all_defines.hpp
// included in all source files -- almkglor
#define INTPTR_MIN		(-2147483647-1)
#define INTPTR_MAX		(2147483647)
#endif // MY_COMPILER

class Generic;
class Symbol;
class Cons;
class Closure;
class KClosure;

namespace Object {

/*-----------------------------------------------------------------------------
Declare
-----------------------------------------------------------------------------*/
	class ref;
	template<typename T> struct tag_traits;
	/*assume we won't ever need more than 7 bits of tag*/
	typedef unsigned char tag_type;

	template<typename T> static inline ref to_ref(T);
	template<typename T> static inline bool _is_a(ref);
	template<typename T> static inline T _as_a(ref);

	static inline ref t(void);
	static inline bool _is_t(ref);

	static inline ref nil(void);
	static inline bool _is_nil(ref);

	static inline ref from_a_scaled_int(int);
	static inline int to_a_scaled_int(ref);
}

void throw_TypeError(Object::ref, char const*);
void throw_RangeError(char const*);

template<typename T> static inline bool is_a(Object::ref);
template<typename T> static inline T as_a(Object::ref);

static inline bool is_t(Object::ref);

namespace Object {

/*-----------------------------------------------------------------------------
Configuration
-----------------------------------------------------------------------------*/

	static const unsigned char tag_bits = 2;// can bump up to 3 maybe...

	template<> struct tag_traits<int> {
		static const tag_type tag = 0x1;
	};
	template<> struct tag_traits<Generic*> {
		static const tag_type tag = 0x0;
	};
	template<> struct tag_traits<Symbol*> {
		static const tag_type tag = 0x2;
	};
	template<> struct tag_traits<UnicodeChar> {
		static const tag_type tag = 0x3;
	};

/*-----------------------------------------------------------------------------
Provided information
-----------------------------------------------------------------------------*/

	static const tag_type alignment = 1 << tag_bits;
	static const tag_type tag_mask = alignment - 1;

	/*the real range is the smaller of the range of intptr_t
	shifted down by tag bits, or the range of the `int' type
	*/
	static const intptr_t smallint_min =
		(sizeof(int) >= sizeof(intptr_t)) ?
			INTPTR_MIN >> tag_bits :
		/*otherwise*/
			INT_MIN;
	static const intptr_t smallint_max =
		(sizeof(int) >= sizeof(intptr_t)) ?
			INTPTR_MAX >> tag_bits :
		/*otherwise*/
			INT_MAX;

	/*value for "t"*/
	static const intptr_t t_value = ~((intptr_t) tag_mask);

/*-----------------------------------------------------------------------------
The tagged pointer type
-----------------------------------------------------------------------------*/

	/*stefano prefers to use:
		typedef void* ref;
	or maybe:
		typedef intptr_t ref;
	I may change this later on, but for now
	I want to see whether the conceptual
	separation will help and if compilers,
	in general, will be smart enough to
	optimize away the structure.
	*/
	class ref {
	private:
		intptr_t dat;
		ref(intptr_t x) : dat(x) {}
	public:
		ref(void) : dat(0) {}
		inline bool operator==(ref b) {
			return dat == b.dat;
		}
		inline bool operator!=(ref b) {
			return dat != b.dat;
		}
		inline bool operator!(void) {
			return dat == 0;
		}

		/*safe bool idiom*/
		typedef intptr_t (ref::*unspecified_bool_type);
		inline operator unspecified_bool_type(void) {
			return dat != 0 ? &ref::dat : 0;
		}

		template<typename T> friend ref to_ref(T);
		template<typename T> friend bool _is_a(ref);
		template<typename T> friend T _as_a(ref);

		friend int to_a_scaled_int(ref);
		friend ref from_a_scaled_int(int);

		friend ref t(void);
		friend bool _is_t(ref);
	};

/*-----------------------------------------------------------------------------
Tagged pointer factories
-----------------------------------------------------------------------------*/

	template<typename T>
	static inline ref to_ref(T x) {
		/* default to Generic* */
		return to_ref<Generic*>(x);
	}
	template<>
	static inline ref to_ref<Generic*>(Generic* x) {
		intptr_t tmp = reinterpret_cast<intptr_t>(x);
		#ifdef DEBUG
			if(tmp & tag_mask != 0) {
				throw_RangeError("Misaligned pointer");
			}
		#endif
		return ref(tmp + tag_traits<Generic*>::tag);
	}
	template<>
	static inline ref to_ref<Symbol*>(Symbol* x) {
		intptr_t tmp = reinterpret_cast<intptr_t>(x);
		#ifdef DEBUG
			if(tmp & tag_mask != 0) {
				throw_RangeError("Misaligned pointer");
			}
		#endif
		return ref(tmp + tag_traits<Symbol*>::tag);
	}
	template<>
	static inline ref to_ref<int>(int x) {
		#ifdef DEBUG
			#if (INT_MAX >= INTPTR_MAX) || (INT_MIN <= INTPTR_MIN)
				if(x < smallint_min || x > smallint_max) {
					throw_RangeError(
						"int out of range of smallint"
					);
				}
			#endif
		#endif
		intptr_t tmp = (((intptr_t) x) << tag_bits);
		return ref(tmp + tag_traits<int>::tag);
	}
	template<>
	static inline ref to_ref<UnicodeChar>(UnicodeChar x) {
		intptr_t tmp = x.dat << tag_bits;
		return ref(tmp + tag_traits<UnicodeChar>::tag);
	}

	/*no checking, even in debug mode... achtung!*/
	static inline ref from_a_scaled_int(int x) {
                return ref((((intptr_t) x)<<tag_bits) + tag_traits<int>::tag);
	}

	static inline ref nil(void) {
		return ref();
	}
	static inline ref t(void) {
		return ref(t_value);
	}

/*-----------------------------------------------------------------------------
Tagged pointer checking
-----------------------------------------------------------------------------*/

	static inline bool _is_nil(ref obj) {
		return !obj;
	}
	static inline bool _is_t(ref obj) {
		return obj.dat == t_value;
	}

	template<typename T>
	static inline bool _is_a(ref obj) {
		if(tag_traits<T>::tag != 0x0) {
			return (obj.dat & tag_mask) == tag_traits<T>::tag;
		} else {
			return (obj.dat & tag_mask) == tag_traits<T>::tag
				&& !_is_nil(obj) && !_is_t(obj);
		}
	}

/*-----------------------------------------------------------------------------
Tagged pointer referencing
-----------------------------------------------------------------------------*/

	template<typename T>
	static inline T _as_a(ref obj) {
		#ifdef DEBUG
			if(!_is_a<T>(obj)) {
				throw_TypeError(obj,
					"incorrect type for pointer"
				);
			}
		#endif
		intptr_t tmp = obj.dat;
		return reinterpret_cast<T>(tmp - tag_traits<T>::tag);
		/*use subtraction instead of masking, in order to
		allow smart compilers to merge a field access with
		the tag removal. i.e. the pointers are pointers to
		structures, so they will be accessed via fields, and
		in all probability those fields will be at some
		offset from the actual structure address, meaning
		that the processor itself will perform an addition
		to access the field.  The smart compiler can then
		merge the addition of the field offset with the
		subtraction of the tag.
		*/
	}

	template<>
	static inline int _as_a<int>(ref obj) {
		#ifdef DEBUG
			if(!_is_a<int>(obj)) {
				throw_TypeError(obj,
					"incorrect type for small integer"
				);
			}
		#endif
		intptr_t tmp = obj.dat;
		return (int)(tmp >> tag_bits);
	}

	template<>
	static inline UnicodeChar _as_a<UnicodeChar>(ref obj) {
		uint32_t tmp = obj.dat;
		return UnicodeChar(tmp >> tag_bits);
	}

	/*no checking, even in debug mode... achtung!*/
	static inline int to_a_scaled_int(ref obj) {
		intptr_t tmp = obj.dat;
		return (int)((tmp - tag_traits<int>::tag)>>tag_bits);
		/*use subtraction instead of masking, again to
		allow smart compilers to merge tag adding and
		subtracting.  For example the typical case would
		be something like:

		Object::ref result =
			Object::from_a_scaled_int(
				Object::to_a_scaled_int(a) +
				Object::to_a_scaled_int(b)
			);

		The above case can be reduced by the compiler to:

		intptr_t result =
			(tag_traits<int>::tag +
				a - tag_traits<int>::tag +
				b - tag_traits<int>::tag
			);

		It can then do some maths and cancel out a tag:

		intptr_t result = a + b - tag_traits<int>::tag;
		*/
	}

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

	static inline size_t round_up_to_alignment(size_t x) {
		return
		(x & tag_mask) ?      (x + alignment - (x & tag_mask)) :
		/*otherwise*/         x ;
	}

}

/*-----------------------------------------------------------------------------
Reflectors outside of the namespace
-----------------------------------------------------------------------------*/

template<typename T>
static inline bool is_a(Object::ref obj) {
	return Object::_is_a<T>(obj);
}
template<typename T>
static inline T as_a(Object::ref obj) {
	return Object::_as_a<T>(obj);
}
static inline bool is_nil(Object::ref obj) {
	return Object::_is_nil(obj);
}
static inline bool is_t(Object::ref obj) {
	return Object::_is_t(obj);
}

#endif //OBJECTS_H

<commit_msg>inc/objects.hpp: clarified comments on Object::to_a_scaled_int and Object::from_a_scaled_int<commit_after>#ifndef OBJECTS_H
#define OBJECTS_H

/*
Defines an Object::ref type, which is a tagged pointer type.
Usage:
	Object::ref x = Object::to_ref(1);//smallint
	Object::ref y = Object::to_ref(new(hp) Generic()); //object
	if(is_a<int>(x)) {
		std::cout << "x = " << as_a<int>(x) << std::endl;
	}
	if(is_a<Generic*>(y)) {
		std::cout << "y.field = " << as_a<Generic*>(y)->field
			<< std::endl;
	}
*/

#include<stdint.h>
#include<climits>

#include"unichars.hpp"

#ifdef MY_COMPILER
// without these my compiler signals an error -- stefano
// I suggest you try it now with all_defines.hpp
// included in all source files -- almkglor
#define INTPTR_MIN		(-2147483647-1)
#define INTPTR_MAX		(2147483647)
#endif // MY_COMPILER

class Generic;
class Symbol;
class Cons;
class Closure;
class KClosure;

namespace Object {

/*-----------------------------------------------------------------------------
Declare
-----------------------------------------------------------------------------*/
	class ref;
	template<typename T> struct tag_traits;
	/*assume we won't ever need more than 7 bits of tag*/
	typedef unsigned char tag_type;

	template<typename T> static inline ref to_ref(T);
	template<typename T> static inline bool _is_a(ref);
	template<typename T> static inline T _as_a(ref);

	static inline ref t(void);
	static inline bool _is_t(ref);

	static inline ref nil(void);
	static inline bool _is_nil(ref);

	static inline ref from_a_scaled_int(int);
	static inline int to_a_scaled_int(ref);
}

void throw_TypeError(Object::ref, char const*);
void throw_RangeError(char const*);

template<typename T> static inline bool is_a(Object::ref);
template<typename T> static inline T as_a(Object::ref);

static inline bool is_t(Object::ref);

namespace Object {

/*-----------------------------------------------------------------------------
Configuration
-----------------------------------------------------------------------------*/

	static const unsigned char tag_bits = 2;// can bump up to 3 maybe...

	template<> struct tag_traits<int> {
		static const tag_type tag = 0x1;
	};
	template<> struct tag_traits<Generic*> {
		static const tag_type tag = 0x0;
	};
	template<> struct tag_traits<Symbol*> {
		static const tag_type tag = 0x2;
	};
	template<> struct tag_traits<UnicodeChar> {
		static const tag_type tag = 0x3;
	};

/*-----------------------------------------------------------------------------
Provided information
-----------------------------------------------------------------------------*/

	static const tag_type alignment = 1 << tag_bits;
	static const tag_type tag_mask = alignment - 1;

	/*the real range is the smaller of the range of intptr_t
	shifted down by tag bits, or the range of the `int' type
	*/
	static const intptr_t smallint_min =
		(sizeof(int) >= sizeof(intptr_t)) ?
			INTPTR_MIN >> tag_bits :
		/*otherwise*/
			INT_MIN;
	static const intptr_t smallint_max =
		(sizeof(int) >= sizeof(intptr_t)) ?
			INTPTR_MAX >> tag_bits :
		/*otherwise*/
			INT_MAX;

	/*value for "t"*/
	static const intptr_t t_value = ~((intptr_t) tag_mask);

/*-----------------------------------------------------------------------------
The tagged pointer type
-----------------------------------------------------------------------------*/

	/*stefano prefers to use:
		typedef void* ref;
	or maybe:
		typedef intptr_t ref;
	I may change this later on, but for now
	I want to see whether the conceptual
	separation will help and if compilers,
	in general, will be smart enough to
	optimize away the structure.
	*/
	class ref {
	private:
		intptr_t dat;
		ref(intptr_t x) : dat(x) {}
	public:
		ref(void) : dat(0) {}
		inline bool operator==(ref b) {
			return dat == b.dat;
		}
		inline bool operator!=(ref b) {
			return dat != b.dat;
		}
		inline bool operator!(void) {
			return dat == 0;
		}

		/*safe bool idiom*/
		typedef intptr_t (ref::*unspecified_bool_type);
		inline operator unspecified_bool_type(void) {
			return dat != 0 ? &ref::dat : 0;
		}

		template<typename T> friend ref to_ref(T);
		template<typename T> friend bool _is_a(ref);
		template<typename T> friend T _as_a(ref);

		friend int to_a_scaled_int(ref);
		friend ref from_a_scaled_int(int);

		friend ref t(void);
		friend bool _is_t(ref);
	};

/*-----------------------------------------------------------------------------
Tagged pointer factories
-----------------------------------------------------------------------------*/

	template<typename T>
	static inline ref to_ref(T x) {
		/* default to Generic* */
		return to_ref<Generic*>(x);
	}
	template<>
	static inline ref to_ref<Generic*>(Generic* x) {
		intptr_t tmp = reinterpret_cast<intptr_t>(x);
		#ifdef DEBUG
			if(tmp & tag_mask != 0) {
				throw_RangeError("Misaligned pointer");
			}
		#endif
		return ref(tmp + tag_traits<Generic*>::tag);
	}
	template<>
	static inline ref to_ref<Symbol*>(Symbol* x) {
		intptr_t tmp = reinterpret_cast<intptr_t>(x);
		#ifdef DEBUG
			if(tmp & tag_mask != 0) {
				throw_RangeError("Misaligned pointer");
			}
		#endif
		return ref(tmp + tag_traits<Symbol*>::tag);
	}
	template<>
	static inline ref to_ref<int>(int x) {
		#ifdef DEBUG
			#if (INT_MAX >= INTPTR_MAX) || (INT_MIN <= INTPTR_MIN)
				if(x < smallint_min || x > smallint_max) {
					throw_RangeError(
						"int out of range of smallint"
					);
				}
			#endif
		#endif
		intptr_t tmp = (((intptr_t) x) << tag_bits);
		return ref(tmp + tag_traits<int>::tag);
	}
	template<>
	static inline ref to_ref<UnicodeChar>(UnicodeChar x) {
		intptr_t tmp = x.dat << tag_bits;
		return ref(tmp + tag_traits<UnicodeChar>::tag);
	}

	/*no checking, even in debug mode... achtung!*/
	/*This function is used to convert an int computed using
	Object::to_a_scaled_int back to an Object::ref.  It is not
	intended to be used for any other int's.
	This function is intended for optimized smallint
	mathematics.
	*/
	static inline ref from_a_scaled_int(int x) {
                return ref((((intptr_t) x)<<tag_bits) + tag_traits<int>::tag);
	}

	static inline ref nil(void) {
		return ref();
	}
	static inline ref t(void) {
		return ref(t_value);
	}

/*-----------------------------------------------------------------------------
Tagged pointer checking
-----------------------------------------------------------------------------*/

	static inline bool _is_nil(ref obj) {
		return !obj;
	}
	static inline bool _is_t(ref obj) {
		return obj.dat == t_value;
	}

	template<typename T>
	static inline bool _is_a(ref obj) {
		if(tag_traits<T>::tag != 0x0) {
			return (obj.dat & tag_mask) == tag_traits<T>::tag;
		} else {
			return (obj.dat & tag_mask) == tag_traits<T>::tag
				&& !_is_nil(obj) && !_is_t(obj);
		}
	}

/*-----------------------------------------------------------------------------
Tagged pointer referencing
-----------------------------------------------------------------------------*/

	template<typename T>
	static inline T _as_a(ref obj) {
		#ifdef DEBUG
			if(!_is_a<T>(obj)) {
				throw_TypeError(obj,
					"incorrect type for pointer"
				);
			}
		#endif
		intptr_t tmp = obj.dat;
		return reinterpret_cast<T>(tmp - tag_traits<T>::tag);
		/*use subtraction instead of masking, in order to
		allow smart compilers to merge a field access with
		the tag removal. i.e. the pointers are pointers to
		structures, so they will be accessed via fields, and
		in all probability those fields will be at some
		offset from the actual structure address, meaning
		that the processor itself will perform an addition
		to access the field.  The smart compiler can then
		merge the addition of the field offset with the
		subtraction of the tag.
		*/
	}

	template<>
	static inline int _as_a<int>(ref obj) {
		#ifdef DEBUG
			if(!_is_a<int>(obj)) {
				throw_TypeError(obj,
					"incorrect type for small integer"
				);
			}
		#endif
		intptr_t tmp = obj.dat;
		return (int)(tmp >> tag_bits);
	}

	template<>
	static inline UnicodeChar _as_a<UnicodeChar>(ref obj) {
		uint32_t tmp = obj.dat;
		return UnicodeChar(tmp >> tag_bits);
	}

	/*no checking, even in debug mode... achtung!*/
	/*This function is used to convert a smallint Object::ref
	to a useable int that is equal to the "real" int, shifted
	to the left by the number of tag bits (i.e. scaled).  It
	should be used only for optimizing smallint math operations.
	*/
	static inline int to_a_scaled_int(ref obj) {
		intptr_t tmp = obj.dat;
		return (int)((tmp - tag_traits<int>::tag)>>tag_bits);
		/*use subtraction instead of masking, again to
		allow smart compilers to merge tag adding and
		subtracting.  For example the typical case would
		be something like:

		Object::ref result =
			Object::from_a_scaled_int(
				Object::to_a_scaled_int(a) +
				Object::to_a_scaled_int(b)
			);

		The above case can be reduced by the compiler to:

		intptr_t result =
			(tag_traits<int>::tag +
				a - tag_traits<int>::tag +
				b - tag_traits<int>::tag
			);

		It can then do some maths and cancel out a tag:

		intptr_t result = a + b - tag_traits<int>::tag;
		*/
	}

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

	static inline size_t round_up_to_alignment(size_t x) {
		return
		(x & tag_mask) ?      (x + alignment - (x & tag_mask)) :
		/*otherwise*/         x ;
	}

}

/*-----------------------------------------------------------------------------
Reflectors outside of the namespace
-----------------------------------------------------------------------------*/

template<typename T>
static inline bool is_a(Object::ref obj) {
	return Object::_is_a<T>(obj);
}
template<typename T>
static inline T as_a(Object::ref obj) {
	return Object::_as_a<T>(obj);
}
static inline bool is_nil(Object::ref obj) {
	return Object::_is_nil(obj);
}
static inline bool is_t(Object::ref obj) {
	return Object::_is_t(obj);
}

#endif //OBJECTS_H

<|endoftext|>


<commit_before>#ifndef SYMBOLS_H
#define SYMBOLS_H

#include"objects.hpp"
#include"heaps.hpp"
#include"mutexes.hpp"

#include<string>
#include<map>

class SymbolsTable;

class Symbol {
	ValueHolderRef value;
	std::string printname; //utf-8
	AppMutex m;

	Symbol(); //disallowed
	explicit Symbol(std::string x) : printname(x) {};
public:
	void copy_value_to(ValueHolderRef&);
	void set_value(Object::ref);
        std::string getPrintName() { return printname; } // for debugging
	friend class SymbolsTable;
};

class SymbolsTableTraverser {
public:
	virtual void traverse(Symbol*) =0;
	virtual ~SymbolsTableTraverser();
};

class SymbolsTable {
private:
	std::map<std::string, Symbol*> tb;
	AppMutex m;

public:
	Symbol* lookup(std::string);
	inline Symbol* lookup(char const* s) {
		return lookup(std::string(s));
	}
	/*note! no atomicity checks.  assumes that traversal
	occurs only when all other worker threads are suspended.
	*/
	void traverse_symbols(SymbolsTableTraverser*) const;
	~SymbolsTable();
};

#endif //SYMBOLS_H

<commit_msg>inc/symbols.hpp: Defined dtor for SymbolsTableTraverser<commit_after>#ifndef SYMBOLS_H
#define SYMBOLS_H

#include"objects.hpp"
#include"heaps.hpp"
#include"mutexes.hpp"

#include<string>
#include<map>

class SymbolsTable;

class Symbol {
	ValueHolderRef value;
	std::string printname; //utf-8
	AppMutex m;

	Symbol(); //disallowed
	explicit Symbol(std::string x) : printname(x) {};
public:
	void copy_value_to(ValueHolderRef&);
	void set_value(Object::ref);
        std::string getPrintName() { return printname; } // for debugging
	friend class SymbolsTable;
};

class SymbolsTableTraverser {
public:
	virtual void traverse(Symbol*) =0;
	virtual ~SymbolsTableTraverser() { }
};

class SymbolsTable {
private:
	std::map<std::string, Symbol*> tb;
	AppMutex m;

public:
	Symbol* lookup(std::string);
	inline Symbol* lookup(char const* s) {
		return lookup(std::string(s));
	}
	/*note! no atomicity checks.  assumes that traversal
	occurs only when all other worker threads are suspended.
	*/
	void traverse_symbols(SymbolsTableTraverser*) const;
	~SymbolsTable();
};

#endif //SYMBOLS_H

<|endoftext|>


<commit_before>#pragma once

#include <stdint.h>
#include <array>
#include <memory>
#include <functional>

#include <Memory.hpp>

// The NES CPU, the 2A03 (or 2A07 for PAL), is based on the 6502.
class CPU {
public:
    CPU(Memory* mem);

    // Execute next instruction.
    void step();

private:
    void execute(const uint8_t& opcode);

    // Returns value at address in the program counter (PC), then increments the PC.
    uint8_t fetch();
    // Returns 16-bit value, concatenated (in little endian order)
    // from 8-bit values located at addresses PC+1 and PC.
    uint16_t fetch16();
    // Push value on the stack and decrement stack pointer.
    void push(const uint8_t& value);
    // Increment stack pointer and pop value from the stack.
    uint8_t pop();

    // Returns 16-bit value, concatenated (in little endian order)
    // from 8-bit values located at address+1 and address.
    uint16_t read16(const uint16_t& address);
    // Splits 16-bit value into two 8-bit values and push them to stack.
    void push16(const uint16_t& value);
    // Pops two 8-bit values and returns them concatenated as a 16-bit value.
    uint16_t pop16();

    Memory* memory;

    // Tracks number of emulated cycles.
    int cycles;

    // The following are the registers - denoted with the 'r_' prefix.
    // Accumulator. Used for arithmethical and logical operations.
    uint8_t r_a;
    // Index registers. Used for indexed addressing.
    uint8_t r_x, // Can directly alter stack pointer, unlike 'r_y'.
            r_y;
    // Program Counter. Contains the memory address of the next instruction to be executed.
    uint16_t r_pc;
    // Stack Pointer.
    uint8_t r_sp;
    // Status register.
    // Each bit is a boolean flag. Enumerating the bits:
    // 76543210
    // NV-BDIZC
    // (with 0 being the least significant bit)
    // 0: Carry flag.
    // 1: Zero flag. Set if the result of the last instruction was 0.
    // 2: Interrupt inhibit. Disables response to maskable Interrupt Requests (IRQs). Doesn't affect Non-Maskable Interrupts (NMIs)
    // 3: Decimal mode. Would enable BCD (Binary Coded Decimal) mode, but it's disabled on the 2A03.
    // 4: Break Command.
    // 5: (Unused)
    // 6: Overflow flag.
    // 7: Negative flag. Set if the result of the last operation was negative.
    // TODO: Add interface to status flags
    uint8_t r_p;

    // Addressing Modes
    void implied(void (CPU::*instruction)()) {
        (this->*instruction)();
    }
    void accumulator(void (CPU::*instruction)()) { // Special type of 'implied'. May be unnecessary.
        (this->*instruction)();
    }
    void immediate(void (CPU::*instruction)(const uint8_t)) {
        const uint8_t value = fetch();
        (this->*instruction)(value);
    }
    void zeroPage(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch();
        (this->*instruction)(address);
    }
    void zeroPageX(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch() + r_x;
        (this->*instruction)(address);
    }
    void zeroPageY(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch() + r_y;
        (this->*instruction)(address);
    }
    //void relative(Instruction instruction);
    void absolute(void (CPU::*instruction)(const uint16_t&)) {
        const uint16_t address = fetch16();
        (this->*instruction)(address);
    }
    //void absoluteX(Instruction instruction);
    //void absoluteY(Instruction instruction);
    //void indirect(Instruction instruction);
    //void indexedIndirect(Instruction instruction);
    //void indirectIndexed(Instruction instruction);

    // Instructions
    void ADC(); // Add with Carry
    void AND(); // Logical AND
    void ASL(); // Arithmetic Shift Left
    void BCC(); // Branch if Carry Clear
    void BCS(); // Branch if Carry Set
    void BEQ(); // Branch if Equal
    void BIT(); // Bit Test
    void BMI(); // Branch if Minus
    void BNE(); // Branch if Not Equal
    void BPL(); // Branch if Positive
    void BRK(); // Force Interrupt
    void BVC(); // Branch if Overflow Clear
    void BVS(); // Branch if Overflow Set
    void CLC(); // Clear Carry Flag
    void CLD(); // Clear Decimal Mode
    void CLI(); // Clear Interrupt Disable
    void CLV(); // Clear Overflow Flag
    void CMP(); // Compare
    void CPX(); // Compare X Register
    void CPY(); // Compare Y Register
    void DEC(); // Decrement Memory
    void DEX(); // Decrement X Register
    void DEY(); // Decrement Y Register
    void EOR(); // Exclusive OR
    void INC(); // Increment Memory
    void INX(); // Increment X Register
    void INY(); // Increment Y Register
    void JMP(); // Jump
    void JSR(); // Jump to Subroutine
    void LDA(); // Load Accumulator
    void LDX(); // Load X Register
    void LDY(); // Load Y Register
    void LSR(); // Logical Shift Right
    void NOP(); // No Operation
    void ORA(); // Logical Inclusive OR
    void PHA(); // Push Accumulator
    void PHP(); // Push Processor Status
    void PLA(); // Pull Accumulator
    void PLP(); // Pull Processor Status
    void ROL(); // Rotate Left
    void ROR(); // Rotate Right
    void RTI(); // Return from Interrupt
    void RTS(); // Return from Subroutine
    void SBC(); // Subtract with Carry
    void SEC(); // Set Carry Flag
    void SED(); // Set Decimal Flag
    void SEI(); // Set Interrupt Disable
    void STA(); // Store Accumulator
    void STX(); // Store X Register
    void STY(); // Store Y Register
    void TAX(); // Transfer Accumulator to X
    void TAY(); // Transfer Accumulator to Y
    void TSX(); // Transfer Stack Pointer to X
    void TXA(); // Transfer X to Accumulator
    void TXS(); // Transfer X to Stack Pointer
    void TYA(); // Transfer Y to Accumulator
};<commit_msg>Add CPU addressing modes Absolute X and Absolute Y<commit_after>#pragma once

#include <stdint.h>
#include <array>
#include <memory>
#include <functional>

#include <Memory.hpp>

// The NES CPU, the 2A03 (or 2A07 for PAL), is based on the 6502.
class CPU {
public:
    CPU(Memory* mem);

    // Execute next instruction.
    void step();

private:
    void execute(const uint8_t& opcode);

    // Returns value at address in the program counter (PC), then increments the PC.
    uint8_t fetch();
    // Returns 16-bit value, concatenated (in little endian order)
    // from 8-bit values located at addresses PC+1 and PC.
    uint16_t fetch16();
    // Push value on the stack and decrement stack pointer.
    void push(const uint8_t& value);
    // Increment stack pointer and pop value from the stack.
    uint8_t pop();

    // Returns 16-bit value, concatenated (in little endian order)
    // from 8-bit values located at address+1 and address.
    uint16_t read16(const uint16_t& address);
    // Splits 16-bit value into two 8-bit values and push them to stack.
    void push16(const uint16_t& value);
    // Pops two 8-bit values and returns them concatenated as a 16-bit value.
    uint16_t pop16();

    Memory* memory;

    // Tracks number of emulated cycles.
    int cycles;

    // The following are the registers - denoted with the 'r_' prefix.
    // Accumulator. Used for arithmethical and logical operations.
    uint8_t r_a;
    // Index registers. Used for indexed addressing.
    uint8_t r_x, // Can directly alter stack pointer, unlike 'r_y'.
            r_y;
    // Program Counter. Contains the memory address of the next instruction to be executed.
    uint16_t r_pc;
    // Stack Pointer.
    uint8_t r_sp;
    // Status register.
    // Each bit is a boolean flag. Enumerating the bits:
    // 76543210
    // NV-BDIZC
    // (with 0 being the least significant bit)
    // 0: Carry flag.
    // 1: Zero flag. Set if the result of the last instruction was 0.
    // 2: Interrupt inhibit. Disables response to maskable Interrupt Requests (IRQs). Doesn't affect Non-Maskable Interrupts (NMIs)
    // 3: Decimal mode. Would enable BCD (Binary Coded Decimal) mode, but it's disabled on the 2A03.
    // 4: Break Command.
    // 5: (Unused)
    // 6: Overflow flag.
    // 7: Negative flag. Set if the result of the last operation was negative.
    // TODO: Add interface to status flags
    uint8_t r_p;

    // Addressing Modes
    void implied(void (CPU::*instruction)()) {
        (this->*instruction)();
    }
    void accumulator(void (CPU::*instruction)()) { // Special type of 'implied'. May be unnecessary.
        (this->*instruction)();
    }
    void immediate(void (CPU::*instruction)(const uint8_t)) {
        const uint8_t value = fetch();
        (this->*instruction)(value);
    }
    void zeroPage(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch();
        (this->*instruction)(address);
    }
    void zeroPageX(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch() + r_x;
        (this->*instruction)(address);
    }
    void zeroPageY(void (CPU::*instruction)(const uint8_t)) {
        const uint16_t address = fetch() + r_y;
        (this->*instruction)(address);
    }
    //void relative(Instruction instruction);
    void absolute(void (CPU::*instruction)(const uint16_t&)) {
        const uint16_t address = fetch16();
        (this->*instruction)(address);
    }
    void absoluteX(void (CPU::*instruction)(const uint16_t&)) {
        const uint16_t address = fetch16() + r_x;
        (this->*instruction)(address);
    }
    void absoluteY(void (CPU::*instruction)(const uint16_t&)) {
        const uint16_t address = fetch16() + r_y;
        (this->*instruction)(address);
    }
    //void indirect(Instruction instruction);
    //void indexedIndirect(Instruction instruction);
    //void indirectIndexed(Instruction instruction);

    // Instructions
    void ADC(); // Add with Carry
    void AND(); // Logical AND
    void ASL(); // Arithmetic Shift Left
    void BCC(); // Branch if Carry Clear
    void BCS(); // Branch if Carry Set
    void BEQ(); // Branch if Equal
    void BIT(); // Bit Test
    void BMI(); // Branch if Minus
    void BNE(); // Branch if Not Equal
    void BPL(); // Branch if Positive
    void BRK(); // Force Interrupt
    void BVC(); // Branch if Overflow Clear
    void BVS(); // Branch if Overflow Set
    void CLC(); // Clear Carry Flag
    void CLD(); // Clear Decimal Mode
    void CLI(); // Clear Interrupt Disable
    void CLV(); // Clear Overflow Flag
    void CMP(); // Compare
    void CPX(); // Compare X Register
    void CPY(); // Compare Y Register
    void DEC(); // Decrement Memory
    void DEX(); // Decrement X Register
    void DEY(); // Decrement Y Register
    void EOR(); // Exclusive OR
    void INC(); // Increment Memory
    void INX(); // Increment X Register
    void INY(); // Increment Y Register
    void JMP(); // Jump
    void JSR(); // Jump to Subroutine
    void LDA(); // Load Accumulator
    void LDX(); // Load X Register
    void LDY(); // Load Y Register
    void LSR(); // Logical Shift Right
    void NOP(); // No Operation
    void ORA(); // Logical Inclusive OR
    void PHA(); // Push Accumulator
    void PHP(); // Push Processor Status
    void PLA(); // Pull Accumulator
    void PLP(); // Pull Processor Status
    void ROL(); // Rotate Left
    void ROR(); // Rotate Right
    void RTI(); // Return from Interrupt
    void RTS(); // Return from Subroutine
    void SBC(); // Subtract with Carry
    void SEC(); // Set Carry Flag
    void SED(); // Set Decimal Flag
    void SEI(); // Set Interrupt Disable
    void STA(); // Store Accumulator
    void STX(); // Store X Register
    void STY(); // Store Y Register
    void TAX(); // Transfer Accumulator to X
    void TAY(); // Transfer Accumulator to Y
    void TSX(); // Transfer Stack Pointer to X
    void TXA(); // Transfer X to Accumulator
    void TXS(); // Transfer X to Stack Pointer
    void TYA(); // Transfer Y to Accumulator
};<|endoftext|>