<commit_before>#include <lightstep/tracer.h>
#include <algorithm>
#include "../src/auto_recorder.h"
#include "../src/lightstep_tracer_impl.h"
#include "../src/manual_recorder.h"
#include "counting_metrics_observer.h"
#include "in_memory_transporter.h"
#include "testing_condition_variable_wrapper.h"

#define CATCH_CONFIG_MAIN
#include <lightstep/catch/catch.hpp>

using namespace lightstep;
using namespace opentracing;

static int LookupSpansDropped(const collector::ReportRequest& report) {
  if (!report.has_internal_metrics()) {
    return 0;
  }
  auto& counts = report.internal_metrics().counts();
  auto iter = std::find_if(counts.begin(), counts.end(),
                           [](const collector::MetricsSample& sample) {
                             return sample.name() == "spans.dropped";
                           });
  if (iter == counts.end()) {
    return 0;
  }
  if (iter->value_case() != collector::MetricsSample::kIntValue) {
    std::cerr << "spans.dropped not of type int\n";
    std::terminate();
  }
  return static_cast<int>(iter->int_value());
}

TEST_CASE("auto_recorder") {
  Logger logger{};
  auto metrics_observer = new CountingMetricsObserver{};
  LightStepTracerOptions options;
  options.reporting_period = std::chrono::milliseconds{2};
  options.max_buffered_spans = 5;
  options.metrics_observer.reset(metrics_observer);
  auto in_memory_transporter = new InMemorySyncTransporter{};
  auto condition_variable = new TestingConditionVariableWrapper{};
  auto recorder = new AutoRecorder{
      logger, std::move(options),
      std::unique_ptr<SyncTransporter>{in_memory_transporter},
      std::unique_ptr<ConditionVariableWrapper>{condition_variable}};
  auto tracer = std::shared_ptr<opentracing::Tracer>{
      new LightStepTracerImpl{std::unique_ptr<Recorder>{recorder}}};
  CHECK(tracer);

  SECTION(
      "The writer thread waits until `now() + options.reporting_period` to "
      "send a report") {
    auto now = condition_variable->Now();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(event->timeout() == now + options.reporting_period);
  }

  SECTION(
      "If the writer thread takes longer than `options.reporting_period` to "
      "run, then it runs again immediately upon finishing.") {
    auto now = condition_variable->Now() + 2 * options.reporting_period;
    condition_variable->WaitTillNextEvent();
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->set_now(now);
    condition_variable->Step();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(condition_variable->Now() == now);
    CHECK(event->timeout() == now);
  }

  SECTION(
      "If the writer thread takes time between 0 and "
      "`options.reporting_period` to run, then it subtracts the elapse time "
      "from the next timeout") {
    auto now = condition_variable->Now() + 3 * options.reporting_period / 2;
    condition_variable->WaitTillNextEvent();
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->set_now(now);
    condition_variable->Step();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(condition_variable->Now() == now);
    CHECK(event->timeout() == now + options.reporting_period / 2);
  }

  SECTION(
      "If the transporter's SendReport function throws, we drop all subsequent "
      "spans.") {
    logger.set_level(LogLevel::off);
    in_memory_transporter->set_should_throw(true);

    // Wait until the writer thread is ready to run.
    condition_variable->WaitTillNextEvent();

    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->Step();

    // Create another span
    span = tracer->StartSpan("abc");
    span->Finish();

    tracer->Close();

    // Verify no spans were transported.
    CHECK(in_memory_transporter->spans().size() == 0);
  }

  SECTION(
      "Dropped spans counts get sent in the next ReportRequest, and cleared in "
      "the following ReportRequest.") {
    condition_variable->set_block_notify_all(true);
    for (size_t i = 0; i < options.max_buffered_spans.value() + 1; ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    // Check that a NotifyAllEvent gets added when the buffer overflows
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::NotifyAllEvent*>(
              condition_variable->next_event()) != nullptr);

    // Wait until the first report gets sent
    condition_variable->Step();
    condition_variable->Step();
    condition_variable->set_block_notify_all(false);

    auto span = tracer->StartSpan("xyz");
    CHECK(span);
    span->Finish();
    // Ensure that the second report gets sent.
    condition_variable->Step();
    condition_variable->Step();

    auto reports = in_memory_transporter->reports();
    CHECK(reports.size() == 2);
    CHECK(LookupSpansDropped(reports.at(0)) == 1);
    CHECK(reports.at(0).spans_size() == options.max_buffered_spans.value());
    CHECK(LookupSpansDropped(reports.at(1)) == 0);
    CHECK(reports.at(1).spans_size() == 1);
  }

  SECTION(
      "MetricsObserver::OnFlush gets called whenever the recorder is "
      "successfully flushed.") {
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_flushes == 1);
  }

  SECTION(
      "MetricsObserver::OnSpansSent gets called with the number of spans "
      "successfully transported") {
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_spans_sent == 2);
  }

  SECTION(
      "MetricsObserver::OnSpansDropped gets called when spans are dropped.") {
    condition_variable->set_block_notify_all(true);
    for (size_t i = 0; i < options.max_buffered_spans.value() + 1; ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    condition_variable->set_block_notify_all(false);
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_spans_dropped == 1);
  }
}

TEST_CASE("manual_recorder") {
  Logger logger{};
  auto metrics_observer = new CountingMetricsObserver{};
  LightStepTracerOptions options;
  options.max_buffered_spans = 5;
  options.metrics_observer.reset(metrics_observer);
  auto in_memory_transporter = new InMemoryAsyncTransporter{};
  auto recorder = new ManualRecorder{
      logger, std::move(options),
      std::unique_ptr<AsyncTransporter>{in_memory_transporter}};
  auto tracer = std::shared_ptr<LightStepTracer>{
      new LightStepTracerImpl{std::unique_ptr<Recorder>{recorder}}};
  CHECK(tracer);

  SECTION("Buffered spans get transported after Flush is manually called.") {
    auto span = tracer->StartSpan("abc");
    CHECK(span);
    span->Finish();
    CHECK(in_memory_transporter->reports().size() == 0);
    CHECK(tracer->Flush());
    in_memory_transporter->Write();
    CHECK(in_memory_transporter->reports().size() == 1);
  }

  SECTION("Flush fails if a report is already being sent.") {
    auto span1 = tracer->StartSpan("abc");
    CHECK(span1);
    span1->Finish();
    CHECK(tracer->Flush());
    auto span2 = tracer->StartSpan("xyz");
    CHECK(span2);
    span2->Finish();
    CHECK(!tracer->Flush());
  }

  SECTION(
      "If the tranporter fails, it's spans are reported as dropped in the "
      "following report.") {
    logger.set_level(LogLevel::off);
    auto span1 = tracer->StartSpan("abc");
    CHECK(span1);
    span1->Finish();
    CHECK(tracer->Flush());
    in_memory_transporter->Fail(
        std::make_error_code(std::errc::network_unreachable));

    auto span2 = tracer->StartSpan("xyz");
    CHECK(span2);
    span2->Finish();
    CHECK(tracer->Flush());
    in_memory_transporter->Write();
    CHECK(LookupSpansDropped(in_memory_transporter->reports().at(0)) == 1);
  }

  SECTION("Flush is called when the tracer's buffer is filled.") {
    for (size_t i = 0; i < options.max_buffered_spans.value(); ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    in_memory_transporter->Write();
    CHECK(in_memory_transporter->reports().size() == 1);
  }

  SECTION(
      "MetricsObserver::OnFlush gets called whenever the recorder is "
      "successfully flushed.") {
    auto span = tracer->StartSpan("abc");
    span->Finish();
    tracer->Flush();
    in_memory_transporter->Write();
    CHECK(metrics_observer->num_flushes == 1);
  }

  SECTION(
      "MetricsObserver::OnSpansSent gets called with the number of spans "
      "successfully transported") {
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    tracer->Flush();
    in_memory_transporter->Write();
    CHECK(metrics_observer->num_spans_sent == 2);
  }

  SECTION(
      "MetricsObserver::OnSpansDropped gets called when spans are dropped.") {
    logger.set_level(LogLevel::off);
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    tracer->Flush();
    in_memory_transporter->Fail(
        std::make_error_code(std::errc::network_unreachable));
    CHECK(metrics_observer->num_spans_dropped == 2);
  }
}
<commit_msg>Fix testing bug.<commit_after>#include <lightstep/tracer.h>
#include <algorithm>
#include "../src/auto_recorder.h"
#include "../src/lightstep_tracer_impl.h"
#include "../src/manual_recorder.h"
#include "counting_metrics_observer.h"
#include "in_memory_transporter.h"
#include "testing_condition_variable_wrapper.h"

#define CATCH_CONFIG_MAIN
#include <lightstep/catch/catch.hpp>

using namespace lightstep;
using namespace opentracing;

static int LookupSpansDropped(const collector::ReportRequest& report) {
  if (!report.has_internal_metrics()) {
    return 0;
  }
  auto& counts = report.internal_metrics().counts();
  auto iter = std::find_if(counts.begin(), counts.end(),
                           [](const collector::MetricsSample& sample) {
                             return sample.name() == "spans.dropped";
                           });
  if (iter == counts.end()) {
    return 0;
  }
  if (iter->value_case() != collector::MetricsSample::kIntValue) {
    std::cerr << "spans.dropped not of type int\n";
    std::terminate();
  }
  return static_cast<int>(iter->int_value());
}

TEST_CASE("auto_recorder") {
  Logger logger{};
  auto metrics_observer = new CountingMetricsObserver{};
  LightStepTracerOptions options;
  const auto reporting_period = std::chrono::milliseconds{2};
  const auto max_buffered_spans = 5;
  options.reporting_period = reporting_period;
  options.max_buffered_spans = max_buffered_spans;
  options.metrics_observer.reset(metrics_observer);
  auto in_memory_transporter = new InMemorySyncTransporter{};
  auto condition_variable = new TestingConditionVariableWrapper{};
  auto recorder = new AutoRecorder{
      logger, std::move(options),
      std::unique_ptr<SyncTransporter>{in_memory_transporter},
      std::unique_ptr<ConditionVariableWrapper>{condition_variable}};
  auto tracer = std::shared_ptr<opentracing::Tracer>{
      new LightStepTracerImpl{std::unique_ptr<Recorder>{recorder}}};
  CHECK(tracer);

  SECTION(
      "The writer thread waits until `now() + reporting_period` to "
      "send a report") {
    auto now = condition_variable->Now();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(event->timeout() == now + reporting_period);
  }

  SECTION(
      "If the writer thread takes longer than `reporting_period` to run, then "
      "it runs again immediately upon finishing.") {
    auto now = condition_variable->Now() + 2 * reporting_period;
    condition_variable->WaitTillNextEvent();
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->set_now(now);
    condition_variable->Step();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(condition_variable->Now() == now);
    CHECK(event->timeout() == now);
  }

  SECTION(
      "If the writer thread takes time between 0 and `reporting_period` to "
      "run, then it subtracts the elapse time from the next timeout") {
    auto now = condition_variable->Now() + 3 * reporting_period / 2;
    condition_variable->WaitTillNextEvent();
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->set_now(now);
    condition_variable->Step();
    condition_variable->WaitTillNextEvent();
    auto event = condition_variable->next_event();
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::WaitEvent*>(
              event) != nullptr);
    CHECK(condition_variable->Now() == now);
    CHECK(event->timeout() == now + reporting_period / 2);
  }

  SECTION(
      "If the transporter's SendReport function throws, we drop all subsequent "
      "spans.") {
    logger.set_level(LogLevel::off);
    in_memory_transporter->set_should_throw(true);

    // Wait until the writer thread is ready to run.
    condition_variable->WaitTillNextEvent();

    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->Step();

    // Create another span
    span = tracer->StartSpan("abc");
    span->Finish();

    tracer->Close();

    // Verify no spans were transported.
    CHECK(in_memory_transporter->spans().size() == 0);
  }

  SECTION(
      "Dropped spans counts get sent in the next ReportRequest, and cleared in "
      "the following ReportRequest.") {
    condition_variable->set_block_notify_all(true);
    for (size_t i = 0; i < max_buffered_spans + 1; ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    // Check that a NotifyAllEvent gets added when the buffer overflows
    CHECK(dynamic_cast<const TestingConditionVariableWrapper::NotifyAllEvent*>(
              condition_variable->next_event()) != nullptr);

    // Wait until the first report gets sent
    condition_variable->Step();
    condition_variable->Step();
    condition_variable->set_block_notify_all(false);

    auto span = tracer->StartSpan("xyz");
    CHECK(span);
    span->Finish();
    // Ensure that the second report gets sent.
    condition_variable->Step();
    condition_variable->Step();

    auto reports = in_memory_transporter->reports();
    CHECK(reports.size() == 2);
    CHECK(LookupSpansDropped(reports.at(0)) == 1);
    CHECK(reports.at(0).spans_size() == max_buffered_spans);
    CHECK(LookupSpansDropped(reports.at(1)) == 0);
    CHECK(reports.at(1).spans_size() == 1);
  }

  SECTION(
      "MetricsObserver::OnFlush gets called whenever the recorder is "
      "successfully flushed.") {
    auto span = tracer->StartSpan("abc");
    span->Finish();
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_flushes == 1);
  }

  SECTION(
      "MetricsObserver::OnSpansSent gets called with the number of spans "
      "successfully transported") {
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_spans_sent == 2);
  }

  SECTION(
      "MetricsObserver::OnSpansDropped gets called when spans are dropped.") {
    condition_variable->set_block_notify_all(true);
    for (size_t i = 0; i < max_buffered_spans + 1; ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    condition_variable->set_block_notify_all(false);
    condition_variable->Step();
    tracer->Close();
    CHECK(metrics_observer->num_spans_dropped == 1);
  }
}

TEST_CASE("manual_recorder") {
  Logger logger{};
  auto metrics_observer = new CountingMetricsObserver{};
  LightStepTracerOptions options;
  const auto max_buffered_spans = 5;
  options.max_buffered_spans = max_buffered_spans;
  options.metrics_observer.reset(metrics_observer);
  auto in_memory_transporter = new InMemoryAsyncTransporter{};
  auto recorder = new ManualRecorder{
      logger, std::move(options),
      std::unique_ptr<AsyncTransporter>{in_memory_transporter}};
  auto tracer = std::shared_ptr<LightStepTracer>{
      new LightStepTracerImpl{std::unique_ptr<Recorder>{recorder}}};
  CHECK(tracer);

  SECTION("Buffered spans get transported after Flush is manually called.") {
    auto span = tracer->StartSpan("abc");
    CHECK(span);
    span->Finish();
    CHECK(in_memory_transporter->reports().size() == 0);
    CHECK(tracer->Flush());
    in_memory_transporter->Write();
    CHECK(in_memory_transporter->reports().size() == 1);
  }

  SECTION("Flush fails if a report is already being sent.") {
    auto span1 = tracer->StartSpan("abc");
    CHECK(span1);
    span1->Finish();
    CHECK(tracer->Flush());
    auto span2 = tracer->StartSpan("xyz");
    CHECK(span2);
    span2->Finish();
    CHECK(!tracer->Flush());
  }

  SECTION(
      "If the tranporter fails, it's spans are reported as dropped in the "
      "following report.") {
    logger.set_level(LogLevel::off);
    auto span1 = tracer->StartSpan("abc");
    CHECK(span1);
    span1->Finish();
    CHECK(tracer->Flush());
    in_memory_transporter->Fail(
        std::make_error_code(std::errc::network_unreachable));

    auto span2 = tracer->StartSpan("xyz");
    CHECK(span2);
    span2->Finish();
    CHECK(tracer->Flush());
    in_memory_transporter->Write();
    CHECK(LookupSpansDropped(in_memory_transporter->reports().at(0)) == 1);
  }

  SECTION("Flush is called when the tracer's buffer is filled.") {
    for (size_t i = 0; i < max_buffered_spans; ++i) {
      auto span = tracer->StartSpan("abc");
      CHECK(span);
      span->Finish();
    }
    in_memory_transporter->Write();
    CHECK(in_memory_transporter->reports().size() == 1);
  }

  SECTION(
      "MetricsObserver::OnFlush gets called whenever the recorder is "
      "successfully flushed.") {
    auto span = tracer->StartSpan("abc");
    span->Finish();
    tracer->Flush();
    in_memory_transporter->Write();
    CHECK(metrics_observer->num_flushes == 1);
  }

  SECTION(
      "MetricsObserver::OnSpansSent gets called with the number of spans "
      "successfully transported") {
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    tracer->Flush();
    in_memory_transporter->Write();
    CHECK(metrics_observer->num_spans_sent == 2);
  }

  SECTION(
      "MetricsObserver::OnSpansDropped gets called when spans are dropped.") {
    logger.set_level(LogLevel::off);
    auto span1 = tracer->StartSpan("abc");
    span1->Finish();
    auto span2 = tracer->StartSpan("abc");
    span2->Finish();
    tracer->Flush();
    in_memory_transporter->Fail(
        std::make_error_code(std::errc::network_unreachable));
    CHECK(metrics_observer->num_spans_dropped == 2);
  }
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: eth_tap.cc,v 1.2 2002/03/09 01:04:49 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// eth_tap.cc  - TAP interface
//
// Example configuration:
//   ifconfig tap0 10.0.0.123 up
//   route add -host 10.0.0.124 gw 10.0.0.123
// Testing:
//   in one window, cat /dev/tap0
//   in another window, ping 10.0.0.124
//   you should see data coming out of /dev/tap0 with each ping.

#include "bochs.h"
#define LOG_THIS bx_ne2k.

#include <signal.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>

#define TAP_VIRTUAL_HW_ADDR             0xDEADBEEF
#define BX_ETH_TAP_LOGGING 1
#define BX_PACKET_BUFSIZ 2048	// Enough for an ether frame

//
//  Define the class. This is private to this module
//
class bx_tap_pktmover_c : public eth_pktmover_c {
public:
  bx_tap_pktmover_c(const char *netif, const char *macaddr,
		     eth_rx_handler_t rxh,
		     void *rxarg);
  void sendpkt(void *buf, unsigned io_len);
private:
  int fd;
  int rx_timer_index;
  static void rx_timer_handler(void *);
  void rx_timer ();
  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
};

//
//  Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_tap_locator_c : public eth_locator_c {
public:
  bx_tap_locator_c(void) : eth_locator_c("tap") {}
protected:
  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
			   eth_rx_handler_t rxh,
			   void *rxarg) {
    return (new bx_tap_pktmover_c(netif, macaddr, rxh, rxarg));
  }
} bx_tap_match;

//
// Define the methods for the bx_tap_pktmover derived class
//

// the constructor
bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif,
				       const char *macaddr,
				       eth_rx_handler_t rxh,
				       void *rxarg)
{
  int flags;
  char filename[BX_PATHNAME_LEN];
  if (strncmp (netif, "tap", 3) != 0) {
    BX_PANIC (("eth_tap: interface name (%s) must be tap0..tap15", netif));
  }
  sprintf (filename, "/dev/%s", netif);

  // check if the TAP devices is running, and turn on ARP.  This is based
  // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
  int sock = socket( AF_INET, SOCK_DGRAM, 0 );
  if (sock < 0) {
    BX_PANIC (("socket creation: %s", strerror(errno)));
    return;
  }
  struct ifreq ifr;
  memset( &ifr, 0, sizeof(ifr) );
  strncpy( ifr.ifr_name, netif, sizeof(ifr.ifr_name) );
  if( ioctl( sock, SIOCGIFFLAGS, &ifr ) < 0 ){
    BX_PANIC (("SIOCGIFFLAGS: %s", strerror (errno)));
    close(sock);
    return;
  }
  if( !(ifr.ifr_flags & IFF_RUNNING ) ){
    BX_PANIC (("%s device is not running", netif));
    close(sock);
    return;
  }
  if( (ifr.ifr_flags & IFF_NOARP ) ){
    BX_INFO (("turn on ARP for %s device", netif));
    ifr.ifr_flags &= ~IFF_NOARP;
    if( ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0 ) {
      BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno)));
      close(sock);
      return;
    }
  }
  close(sock);

  fd = open (filename, O_RDWR);
  if (fd < 0) {
    BX_PANIC (("open failed on %s: %s", netif, strerror (errno)));
    return;
  }

  /* set O_ASYNC flag so that we can poll with read() */
  if ((flags = fcntl( fd, F_GETFL)) < 0) {
    BX_PANIC (("getflags on tap device: %s", strerror (errno)));
  }
  flags |= O_NONBLOCK;
  if (fcntl( fd, F_SETFL, flags ) < 0) {
    BX_PANIC (("set tap device flags: %s", strerror (errno)));
  }

  BX_INFO (("eth_tap: opened %s device", netif));

#if BX_ETH_TAP_LOGGING
  // Start the rx poll
  this->rx_timer_index =
    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
				1, 1); // continuous, active
  this->rxh   = rxh;
  this->rxarg = rxarg;
  // eventually Bryce wants txlog to dump in pcap format so that
  // tcpdump -r FILE can read it and interpret packets.
  txlog = fopen ("ne2k-tx.log", "wb");
  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
  fprintf (txlog_txt, "tap packetmover readable log file\n");
  fprintf (txlog_txt, "net IF = %s\n", netif);
  fprintf (txlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (txlog_txt, "\n--\n");
  fflush (txlog_txt);

  rxlog = fopen ("ne2k-rx.log", "wb");
  if (!rxlog) BX_PANIC (("open ne2k-rx.log failed"));
  rxlog_txt = fopen ("ne2k-rxdump.txt", "wb");
  if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed"));
  fprintf (rxlog_txt, "tap packetmover readable log file\n");
  fprintf (rxlog_txt, "net IF = %s\n", netif);
  fprintf (rxlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (rxlog_txt, "\n--\n");
  fflush (rxlog_txt);

#endif
}

void
bx_tap_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
  Bit8u txbuf[BX_PACKET_BUFSIZ];
  txbuf[0] = 0;
  txbuf[1] = 0;
  memcpy (txbuf+2, buf, io_len);
  unsigned int size = write (fd, txbuf, io_len+2);
  if (size != io_len+2) {
    BX_PANIC (("write on tap device: %s", strerror (errno)));
  } else {
    BX_INFO (("wrote %d bytes + 2 byte pad on tap", io_len));
  }
#if BX_ETH_TAP_LOGGING
  BX_DEBUG (("sendpkt length %u", io_len));
  // dump raw bytes to a file, eventually dump in pcap format so that
  // tcpdump -r FILE can interpret them for us.
  int n = fwrite (buf, io_len, 1, txlog);
  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
  // dump packet in hex into an ascii log file
  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
  Bit8u *charbuf = (Bit8u *)buf;
  for (n=0; n<io_len; n++) {
    if (((n % 16) == 0) && n>0)
      fprintf (txlog_txt, "\n");
    fprintf (txlog_txt, "%02x ", charbuf[n]);
  }
  fprintf (txlog_txt, "\n--\n");
  // flush log so that we see the packets as they arrive w/o buffering
  fflush (txlog);
  fflush (txlog_txt);
#endif
}

void bx_tap_pktmover_c::rx_timer_handler (void *this_ptr)
{
  bx_tap_pktmover_c *class_ptr = (bx_tap_pktmover_c *) this_ptr;
  class_ptr->rx_timer();
}

void bx_tap_pktmover_c::rx_timer ()
{
  int nbytes;
  Bit8u buf[BX_PACKET_BUFSIZ];
  Bit8u *rxbuf;
  if (fd<0) return;
  nbytes = read (fd, buf, sizeof(buf));

  // hack: discard first two bytes
  rxbuf = buf+2;
  nbytes-=2;

  // hack: TAP device likes to create an ethernet header which has
  // the same source and destination address FE:FD:00:00:00:00.
  // Change the dest address to FE:FD:00:00:00:01.
  rxbuf[5] = 1;

  if (nbytes>0)
    BX_INFO (("tap read returned %d bytes", nbytes));
  if (nbytes<0) {
    if (errno != EAGAIN)
      BX_ERROR (("tap read error: %s", strerror(errno)));
    return;
  }
#if BX_ETH_TAP_LOGGING
  if (nbytes > 0) {
    BX_DEBUG (("receive packet length %u", nbytes));
    // dump raw bytes to a file, eventually dump in pcap format so that
    // tcpdump -r FILE can interpret them for us.
    int n = fwrite (rxbuf, nbytes, 1, rxlog);
    if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
    // dump packet in hex into an ascii log file
    fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
    for (n=0; n<nbytes; n++) {
      if (((n % 16) == 0) && n>0)
	fprintf (rxlog_txt, "\n");
      fprintf (rxlog_txt, "%02x ", rxbuf[n]);
    }
    fprintf (rxlog_txt, "\n--\n");
    // flush log so that we see the packets as they arrive w/o buffering
    fflush (rxlog);
    fflush (rxlog_txt);
  }
#endif
  BX_DEBUG(("eth_tap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
  if (nbytes < 60) {
    BX_INFO (("packet too short (%d), padding to 60", nbytes));
    nbytes = 60;
  }
  (*rxh)(rxarg, rxbuf, nbytes);
}
<commit_msg>- add instructions for setting it TAP<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: eth_tap.cc,v 1.3 2002/03/09 01:23:21 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// eth_tap.cc  - TAP interface by Bryce Denney
//
// Here's how to get this working.  On the host machine:
//    $ su root
//    # /sbin/insmod ethertap
//    Using /lib/modules/2.2.14-5.0/net/ethertap.o
//    # mknod /dev/tap0 c 36 16          # if not already there
//    # /sbin/ifconfig tap0 10.0.0.1
//    # /sbin/route add -host 10.0.0.2 gw 10.0.0.1
//
// Now you have a tap0 device which you can on the ifconfig output.  The
// tap0 interface has the IP address of 10.0.0.1.  The bochs machine will have
// the IP address 10.0.0.2.
//
// Compile a bochs version from March 8, 2002 or later with --enable-ne2000.
// Add this ne2k line to your .bochsrc to activate the tap device.
//   ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
// Don't change the mac or ethmod!
//
// Boot up DLX Linux in Bochs.  Log in as root and then type the following
// commands to set up networking:
//   # ifconfig eth0 10.0.0.2
//   # route add -net 10.0.0.0
//   # route add default gw 10.0.0.1
// Now you should be able to ping from guest OS to your host machine, if
// you give its IP number.  I'm still having trouble with pings from the
// host machine to the guest, so something is still not right.  But it's
// really close to working!
//
// By setting up packet forwarding (with masquerading) on the host, you should
// be able to get Bochs talking to anyone on the internet.
//

#include "bochs.h"
#define LOG_THIS bx_ne2k.

#include <signal.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>

#define TAP_VIRTUAL_HW_ADDR             0xDEADBEEF
#define BX_ETH_TAP_LOGGING 1
#define BX_PACKET_BUFSIZ 2048	// Enough for an ether frame

//
//  Define the class. This is private to this module
//
class bx_tap_pktmover_c : public eth_pktmover_c {
public:
  bx_tap_pktmover_c(const char *netif, const char *macaddr,
		     eth_rx_handler_t rxh,
		     void *rxarg);
  void sendpkt(void *buf, unsigned io_len);
private:
  int fd;
  int rx_timer_index;
  static void rx_timer_handler(void *);
  void rx_timer ();
  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
};

//
//  Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_tap_locator_c : public eth_locator_c {
public:
  bx_tap_locator_c(void) : eth_locator_c("tap") {}
protected:
  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
			   eth_rx_handler_t rxh,
			   void *rxarg) {
    return (new bx_tap_pktmover_c(netif, macaddr, rxh, rxarg));
  }
} bx_tap_match;

//
// Define the methods for the bx_tap_pktmover derived class
//

// the constructor
bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif,
				       const char *macaddr,
				       eth_rx_handler_t rxh,
				       void *rxarg)
{
  int flags;
  char filename[BX_PATHNAME_LEN];
  if (strncmp (netif, "tap", 3) != 0) {
    BX_PANIC (("eth_tap: interface name (%s) must be tap0..tap15", netif));
  }
  sprintf (filename, "/dev/%s", netif);

  // check if the TAP devices is running, and turn on ARP.  This is based
  // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
  int sock = socket( AF_INET, SOCK_DGRAM, 0 );
  if (sock < 0) {
    BX_PANIC (("socket creation: %s", strerror(errno)));
    return;
  }
  struct ifreq ifr;
  memset( &ifr, 0, sizeof(ifr) );
  strncpy( ifr.ifr_name, netif, sizeof(ifr.ifr_name) );
  if( ioctl( sock, SIOCGIFFLAGS, &ifr ) < 0 ){
    BX_PANIC (("SIOCGIFFLAGS: %s", strerror (errno)));
    close(sock);
    return;
  }
  if( !(ifr.ifr_flags & IFF_RUNNING ) ){
    BX_PANIC (("%s device is not running", netif));
    close(sock);
    return;
  }
  if( (ifr.ifr_flags & IFF_NOARP ) ){
    BX_INFO (("turn on ARP for %s device", netif));
    ifr.ifr_flags &= ~IFF_NOARP;
    if( ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0 ) {
      BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno)));
      close(sock);
      return;
    }
  }
  close(sock);

  fd = open (filename, O_RDWR);
  if (fd < 0) {
    BX_PANIC (("open failed on %s: %s", netif, strerror (errno)));
    return;
  }

  /* set O_ASYNC flag so that we can poll with read() */
  if ((flags = fcntl( fd, F_GETFL)) < 0) {
    BX_PANIC (("getflags on tap device: %s", strerror (errno)));
  }
  flags |= O_NONBLOCK;
  if (fcntl( fd, F_SETFL, flags ) < 0) {
    BX_PANIC (("set tap device flags: %s", strerror (errno)));
  }

  BX_INFO (("eth_tap: opened %s device", netif));

#if BX_ETH_TAP_LOGGING
  // Start the rx poll
  this->rx_timer_index =
    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
				1, 1); // continuous, active
  this->rxh   = rxh;
  this->rxarg = rxarg;
  // eventually Bryce wants txlog to dump in pcap format so that
  // tcpdump -r FILE can read it and interpret packets.
  txlog = fopen ("ne2k-tx.log", "wb");
  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
  fprintf (txlog_txt, "tap packetmover readable log file\n");
  fprintf (txlog_txt, "net IF = %s\n", netif);
  fprintf (txlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (txlog_txt, "\n--\n");
  fflush (txlog_txt);

  rxlog = fopen ("ne2k-rx.log", "wb");
  if (!rxlog) BX_PANIC (("open ne2k-rx.log failed"));
  rxlog_txt = fopen ("ne2k-rxdump.txt", "wb");
  if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed"));
  fprintf (rxlog_txt, "tap packetmover readable log file\n");
  fprintf (rxlog_txt, "net IF = %s\n", netif);
  fprintf (rxlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (rxlog_txt, "\n--\n");
  fflush (rxlog_txt);

#endif
}

void
bx_tap_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
  Bit8u txbuf[BX_PACKET_BUFSIZ];
  txbuf[0] = 0;
  txbuf[1] = 0;
  memcpy (txbuf+2, buf, io_len);
  unsigned int size = write (fd, txbuf, io_len+2);
  if (size != io_len+2) {
    BX_PANIC (("write on tap device: %s", strerror (errno)));
  } else {
    BX_INFO (("wrote %d bytes + 2 byte pad on tap", io_len));
  }
#if BX_ETH_TAP_LOGGING
  BX_DEBUG (("sendpkt length %u", io_len));
  // dump raw bytes to a file, eventually dump in pcap format so that
  // tcpdump -r FILE can interpret them for us.
  int n = fwrite (buf, io_len, 1, txlog);
  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
  // dump packet in hex into an ascii log file
  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
  Bit8u *charbuf = (Bit8u *)buf;
  for (n=0; n<io_len; n++) {
    if (((n % 16) == 0) && n>0)
      fprintf (txlog_txt, "\n");
    fprintf (txlog_txt, "%02x ", charbuf[n]);
  }
  fprintf (txlog_txt, "\n--\n");
  // flush log so that we see the packets as they arrive w/o buffering
  fflush (txlog);
  fflush (txlog_txt);
#endif
}

void bx_tap_pktmover_c::rx_timer_handler (void *this_ptr)
{
  bx_tap_pktmover_c *class_ptr = (bx_tap_pktmover_c *) this_ptr;
  class_ptr->rx_timer();
}

void bx_tap_pktmover_c::rx_timer ()
{
  int nbytes;
  Bit8u buf[BX_PACKET_BUFSIZ];
  Bit8u *rxbuf;
  if (fd<0) return;
  nbytes = read (fd, buf, sizeof(buf));

  // hack: discard first two bytes
  rxbuf = buf+2;
  nbytes-=2;

  // hack: TAP device likes to create an ethernet header which has
  // the same source and destination address FE:FD:00:00:00:00.
  // Change the dest address to FE:FD:00:00:00:01.
  rxbuf[5] = 1;

  if (nbytes>0)
    BX_INFO (("tap read returned %d bytes", nbytes));
  if (nbytes<0) {
    if (errno != EAGAIN)
      BX_ERROR (("tap read error: %s", strerror(errno)));
    return;
  }
#if BX_ETH_TAP_LOGGING
  if (nbytes > 0) {
    BX_DEBUG (("receive packet length %u", nbytes));
    // dump raw bytes to a file, eventually dump in pcap format so that
    // tcpdump -r FILE can interpret them for us.
    int n = fwrite (rxbuf, nbytes, 1, rxlog);
    if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
    // dump packet in hex into an ascii log file
    fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
    for (n=0; n<nbytes; n++) {
      if (((n % 16) == 0) && n>0)
	fprintf (rxlog_txt, "\n");
      fprintf (rxlog_txt, "%02x ", rxbuf[n]);
    }
    fprintf (rxlog_txt, "\n--\n");
    // flush log so that we see the packets as they arrive w/o buffering
    fflush (rxlog);
    fflush (rxlog_txt);
  }
#endif
  BX_DEBUG(("eth_tap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
  if (nbytes < 60) {
    BX_INFO (("packet too short (%d), padding to 60", nbytes));
    nbytes = 60;
  }
  (*rxh)(rxarg, rxbuf, nbytes);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>

#include "../include/RRR.h"

using namespace std;

// calculates number of ones or zeros depending on type
int RRR::calcForType(int total, int ones, bool type) {
  return type ? ones : total-ones;
}

// finds index of superblock containing i-th one/zero (type)
int RRR::findSuperblock(int i, bool type) {
  int lo = 0;
  int hi = numSuperblocks;
  while(lo < hi) {
    int mid = (lo+hi)/2;
    int cumsum = calcForType(b*f*(mid+1), superblockCumSum[mid], type);
    if (cumsum < i) {
      lo = mid+1;
    } else {
      hi = mid;
    }
  }
  return lo;
}

// finds index in indBlock containing i-th one/zero (x)
int RRR::findIndexInBlock(int indBlock, int i, bool type) {
  int lo = 0;
  int hi = b;
  while (lo < hi) {
    int mid = (lo+hi)/2;
    int cumsum = \
      calcForType(mid+1, cumSumInBlock[blockClass[indBlock]][blockOffset[indBlock]][mid], type);
    if (cumsum < i) {
      lo = mid+1;
    } else {
      hi = mid;
    }
  }
  return lo;
}

int RRR::getIndBlock(int ind) {
  return ind/b;
}

int RRR::getIndSuperblock(int indBlock) {
  return indBlock/(b*f);
}

int RRR::getCumSumToSuperblock(int indSuperblock, bool type) {
  return (indSuperblock < 0) ? 0 : calcForType((indSuperblock+1)*b*f, superblockCumSum[indSuperblock], type);
}

bool RRR::isBlockStart(int ind) {
  return getIndBlock(ind) != getIndBlock(ind-1);
}

int RRR::nChoosek(int n, int k) {
  if (k > n) return 0;
  if (k*2 > n) k = n-k;
  if (k == 0) return 1;

  int res = n;
  for (int i = 2; i <= k; ++i) {
    res *= (n-i+1);
    res /= i;
  }
  return res;
}

int RRR::select(int i, bool type) {
  // index of superblock containing i-th one/zero
  int indSuperblock = findSuperblock(i, type);

  // cumulative sum of ones/zeros up to previous superblock
  int counter = getCumSumToSuperblock(indSuperblock-1, type);

  int indBlock = indSuperblock*f; // current block index
  // loop through blocks until the sum of i is reached
  while (counter < i) {
    counter += calcForType(b, blockClass[indBlock], type);
    ++indBlock;
  }

  // return to previous block
  --indBlock;
  counter -= calcForType(b, blockClass[indBlock], type);

  // index in indBlock containing (i-counter)-th one
  int indInBlock = findIndexInBlock(indBlock, i-counter, type);

  return indBlock*b + indInBlock;
}

void RRR::construct(vector<bool> bits, int _b, int _f) {
  b = _b;
  f = _f;

  // preprocessing - O(b*2^b) time and memory
  vector<int> blockValToOffset;
  blockValToOffset.resize(1<<b);
  vector<int> indInClass; // index in class
  indInClass.resize(b+1, 0); // b+1 different classes in total (0 ones, .., b ones)
  cumSumInBlock.resize(b+1); // b+1 different classes in total
  for (int i = 0; i < (1<<b); ++i) {
    int classType = __builtin_popcount(i);
    blockValToOffset[i] = indInClass[classType];
    ++indInClass[classType];

    // calculate cumSumInBlock
    cumSumInBlock[classType].resize(nChoosek(b, classType));
    cumSumInBlock[classType][blockValToOffset[i]].resize(b);
    int cumsum = 0;
    for (int j = 0; j < b; ++j) {
      cumsum += !!(i&(1<<(b-j-1)));
      cumSumInBlock[classType][blockValToOffset[i]][j] = cumsum;
    }
  }
  // preprocessing finished

  int n = bits.size();
  numBlocks = (n-1)/b+1;
  numSuperblocks = (n-1)/(b*f)+1;
  blockClass.resize(numBlocks, 0);
  blockOffset.resize(numBlocks);
  superblockCumSum.resize(numSuperblocks);

  int cumsum = 0;
  int blockVal = 0;
  for (int i = 0; i < numBlocks*b; ++i) {
    if (isBlockStart(i)) {
      blockVal = 0; // when new block starts reset block value to zero
    }
    // update block class and offset
    int indBlock = getIndBlock(i);
    blockVal = (blockVal*2) + bits[i]; // TODO: don't limit b to 32
    blockOffset[indBlock] = blockValToOffset[blockVal];
    blockClass[indBlock] += bits[i];

    // update superblockCumSum
    cumsum += bits[i];
    superblockCumSum[getIndSuperblock(i)] = cumsum;
  }
}

// time-complexity - O(b*2^b) for preprocessing
RRR::RRR(vector<bool> bits) {
  int b = max((int)(log2(bits.size()) / 2), 1);
  int f = max((int)pow(log2(bits.size()), 2), 1);
  construct(bits, b, f);
}

// time-complexity - O(b*2^b) for preprocessing
RRR::RRR(vector<bool> bits, int _b, int _f) {
  construct(bits, _b, _f);
}

// number of zeros to position i, inclusive
// time-complexity - same as rank1()
int RRR::rank0(int i) {
  // calculate using number of ones
  return i+1-rank1(i);
}

// number of ones to position i, inclusive
// time-complexity - O(f)
// TODO: convert to O(1), hint: remove looping through each block in superblock and
// use cumulative sum of blocks in superblock instead
int RRR::rank1(int ind) {
  int indBlock = getIndBlock(ind); // block index
  int indSuperblock = getIndSuperblock(ind); // superblock index

  // cumulative sum of ones up to previous superblock
  int counter = getCumSumToSuperblock(indSuperblock-1, true);

  // add sum of ones in all blocks of current superblock up to previous block
  for (int i = indSuperblock*f; i < indBlock; ++i) {
    counter += blockClass[i];
  }
  // add number of ones in current block up to i-th position
  counter += cumSumInBlock[blockClass[indBlock]][blockOffset[indBlock]][ind-indBlock*b];
  return counter;
}

// index of the i-th zero (0-indexed)
// time-complexity - same as select1()
int RRR::select0(int i) {
  return select(i, false);
}

// index of the i-th one (0-indexed)
// time-complexity - O(log(n/(b*f))+f+log(b))
int RRR::select1(int i) {
  return select(i, true);
}

// bit on given index
// time-complexity - same as rank1()
int RRR::access(int ind) {
  return (ind > 0) ? rank1(ind)-rank1(ind-1) : rank1(ind);
}
<commit_msg>Changed parameter in RRR.<commit_after>#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>

#include "../include/RRR.h"

using namespace std;

// calculates number of ones or zeros depending on type
int RRR::calcForType(int total, int ones, bool type) {
  return type ? ones : total-ones;
}

// finds index of superblock containing i-th one/zero (type)
int RRR::findSuperblock(int i, bool type) {
  int lo = 0;
  int hi = numSuperblocks;
  while(lo < hi) {
    int mid = (lo+hi)/2;
    int cumsum = calcForType(b*f*(mid+1), superblockCumSum[mid], type);
    if (cumsum < i) {
      lo = mid+1;
    } else {
      hi = mid;
    }
  }
  return lo;
}

// finds index in indBlock containing i-th one/zero (x)
int RRR::findIndexInBlock(int indBlock, int i, bool type) {
  int lo = 0;
  int hi = b;
  while (lo < hi) {
    int mid = (lo+hi)/2;
    int cumsum = \
      calcForType(mid+1, cumSumInBlock[blockClass[indBlock]][blockOffset[indBlock]][mid], type);
    if (cumsum < i) {
      lo = mid+1;
    } else {
      hi = mid;
    }
  }
  return lo;
}

int RRR::getIndBlock(int ind) {
  return ind/b;
}

int RRR::getIndSuperblock(int indBlock) {
  return indBlock/(b*f);
}

int RRR::getCumSumToSuperblock(int indSuperblock, bool type) {
  return (indSuperblock < 0) ? 0 : calcForType((indSuperblock+1)*b*f, superblockCumSum[indSuperblock], type);
}

bool RRR::isBlockStart(int ind) {
  return getIndBlock(ind) != getIndBlock(ind-1);
}

int RRR::nChoosek(int n, int k) {
  if (k > n) return 0;
  if (k*2 > n) k = n-k;
  if (k == 0) return 1;

  int res = n;
  for (int i = 2; i <= k; ++i) {
    res *= (n-i+1);
    res /= i;
  }
  return res;
}

int RRR::select(int i, bool type) {
  // index of superblock containing i-th one/zero
  int indSuperblock = findSuperblock(i, type);

  // cumulative sum of ones/zeros up to previous superblock
  int counter = getCumSumToSuperblock(indSuperblock-1, type);

  int indBlock = indSuperblock*f; // current block index
  // loop through blocks until the sum of i is reached
  while (counter < i) {
    counter += calcForType(b, blockClass[indBlock], type);
    ++indBlock;
  }

  // return to previous block
  --indBlock;
  counter -= calcForType(b, blockClass[indBlock], type);

  // index in indBlock containing (i-counter)-th one
  int indInBlock = findIndexInBlock(indBlock, i-counter, type);

  return indBlock*b + indInBlock;
}

void RRR::construct(vector<bool> bits, int _b, int _f) {
  b = _b;
  f = _f;

  // preprocessing - O(b*2^b) time and memory
  vector<int> blockValToOffset;
  blockValToOffset.resize(1<<b);
  vector<int> indInClass; // index in class
  indInClass.resize(b+1, 0); // b+1 different classes in total (0 ones, .., b ones)
  cumSumInBlock.resize(b+1); // b+1 different classes in total
  for (int i = 0; i < (1<<b); ++i) {
    int classType = __builtin_popcount(i);
    blockValToOffset[i] = indInClass[classType];
    ++indInClass[classType];

    // calculate cumSumInBlock
    cumSumInBlock[classType].resize(nChoosek(b, classType));
    cumSumInBlock[classType][blockValToOffset[i]].resize(b);
    int cumsum = 0;
    for (int j = 0; j < b; ++j) {
      cumsum += !!(i&(1<<(b-j-1)));
      cumSumInBlock[classType][blockValToOffset[i]][j] = cumsum;
    }
  }
  // preprocessing finished

  int n = bits.size();
  numBlocks = (n-1)/b+1;
  numSuperblocks = (n-1)/(b*f)+1;
  blockClass.resize(numBlocks, 0);
  blockOffset.resize(numBlocks);
  superblockCumSum.resize(numSuperblocks);

  int cumsum = 0;
  int blockVal = 0;
  for (int i = 0; i < numBlocks*b; ++i) {
    if (isBlockStart(i)) {
      blockVal = 0; // when new block starts reset block value to zero
    }
    // update block class and offset
    int indBlock = getIndBlock(i);
    blockVal = (blockVal*2) + bits[i]; // TODO: don't limit b to 32
    blockOffset[indBlock] = blockValToOffset[blockVal];
    blockClass[indBlock] += bits[i];

    // update superblockCumSum
    cumsum += bits[i];
    superblockCumSum[getIndSuperblock(i)] = cumsum;
  }
}

// time-complexity - O(b*2^b) for preprocessing
RRR::RRR(vector<bool> bits) {
  int b = max((int)(floor(log2(bits.size())) / 2), 1);
  int f = max((int)(pow(floor(log2(bits.size())), 2) / b), 1);
  construct(bits, b, f);
}

// time-complexity - O(b*2^b) for preprocessing
RRR::RRR(vector<bool> bits, int _b, int _f) {
  construct(bits, _b, _f);
}

// number of zeros to position i, inclusive
// time-complexity - same as rank1()
int RRR::rank0(int i) {
  // calculate using number of ones
  return i+1-rank1(i);
}

// number of ones to position i, inclusive
// time-complexity - O(f)
// TODO: convert to O(1), hint: remove looping through each block in superblock and
// use cumulative sum of blocks in superblock instead
int RRR::rank1(int ind) {
  int indBlock = getIndBlock(ind); // block index
  int indSuperblock = getIndSuperblock(ind); // superblock index

  // cumulative sum of ones up to previous superblock
  int counter = getCumSumToSuperblock(indSuperblock-1, true);

  // add sum of ones in all blocks of current superblock up to previous block
  for (int i = indSuperblock*f; i < indBlock; ++i) {
    counter += blockClass[i];
  }
  // add number of ones in current block up to i-th position
  counter += cumSumInBlock[blockClass[indBlock]][blockOffset[indBlock]][ind-indBlock*b];
  return counter;
}

// index of the i-th zero (0-indexed)
// time-complexity - same as select1()
int RRR::select0(int i) {
  return select(i, false);
}

// index of the i-th one (0-indexed)
// time-complexity - O(log(n/(b*f))+f+log(b))
int RRR::select1(int i) {
  return select(i, true);
}

// bit on given index
// time-complexity - same as rank1()
int RRR::access(int ind) {
  return (ind > 0) ? rank1(ind)-rank1(ind-1) : rank1(ind);
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: iodebug.cc,v 1.18 2005/11/14 19:03:12 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////

#include "iodev.h"
#if BX_SUPPORT_IODEBUG

bx_iodebug_c bx_iodebug;
bx_iodebug_c *bx_iodebug_ptr;

  struct bx_iodebug_s_type {
    bx_bool enabled;
    unsigned int register_select;
    Bit32u registers[2];
    Bit32u monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
    Bit32u monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
  } bx_iodebug_s;

// Constructor
bx_iodebug_c::bx_iodebug_c( void )
{
  put("IODEBUG");
  settype(IODEBUGLOG);

}

// Destructor
bx_iodebug_c::~bx_iodebug_c( void )
{
}

void bx_iodebug_c::init(void)
{
  int i;

  DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 7);
  DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 7);
  DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 7);
//  fprintf( stderr, "IODEBUG initialized\n");

  bx_iodebug_s.enabled = 0;
  bx_iodebug_s.register_select = 0;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
  }
}

void bx_iodebug_c::reset(unsigned type)
{
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  return( bx_iodebug_ptr->read(addr, io_len) );
}

Bit32u bx_iodebug_c::read( Bit32u addr, unsigned io_len )
{
  if(bx_iodebug_s.enabled) return(0x8A00);
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
  class_ptr->write( addr, dvalue, io_len );
}

void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
{
//  fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);

  if( addr == 0x8A01 && io_len == 2 )
  {
      bx_iodebug_s.registers[bx_iodebug_s.register_select] =
        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
	(dvalue & 0x0000FFFF );
  }

  if( (addr != 0x8A00) || (io_len != 2) ) return;

  if( !bx_iodebug_s.enabled )
  {
    if( dvalue == 0x8A00 )
    {
      bx_iodebug_s.enabled = 1;
//      fprintf(stderr, "IODEBUG enabled\n");
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
    }
    return;
  }

  switch( dvalue )
  {
    case( 0x8A01 ):
      bx_iodebug_s.register_select = 0;
//      fprintf( stderr, "IODEBUG register 0 selected\n");
      break;

    case( 0x8A02 ):
      bx_iodebug_s.register_select = 1;
//      fprintf( stderr, "IODEBUG register 1 selected\n");
      break;

    case( 0x8A80 ):
      bx_iodebug_s.register_select = 0;
      bx_iodebug_c::add_range(
          bx_iodebug_s.registers[0],
	  bx_iodebug_s.registers[1]);
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
      break;

#if BX_DEBUGGER
    case( 0x8AE0 ):
      fprintf( stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
      bx_guard.interrupt_requested=1;
      break;

    case( 0x8AE2):
      fprintf( stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
      BX_CPU(dbg_cpu)->trace = 0;
      break;

    case( 0x8AE3 ):
      fprintf( stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
      BX_CPU(dbg_cpu)->trace = 1;
      break;

    case( 0x8AE4 ):
      fprintf( stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
      BX_CPU(dbg_cpu)->trace_reg = 0;
      break;

    case( 0x8AE5 ):
      fprintf( stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
      BX_CPU(dbg_cpu)->trace_reg = 1;
      break;

#endif

    case( 0x8AFF ):
      bx_iodebug_s.enabled = 0;
//      fprintf( stderr, "IODEBUG device deactivated\n");
//      break;

//    default:
//      fprintf(stderr,"IODEBUG unsupported register code\n");
  }
}

// Static function
void bx_iodebug_c::mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  unsigned int area;
  if( !bx_iodebug_s.enabled ) return;

  area = bx_iodebug_c::range_test( addr, len );
  // Device is enabled, testing address ranges
  if( area )
  {
    area--;
#if BX_DEBUGGER
    fprintf( stdout, "%s @ eip: %08X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
    bx_guard.interrupt_requested=1;
#else
    fprintf( stderr,
             "IODEBUG write to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     area,
	     cpu->get_EIP(),
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned int)addr);

    Bit32u data32 = * (Bit32u *)data;
    Bit16u data16 = (Bit16u)data32;
    Bit8u  data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%02X\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%04X\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%08X\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  unsigned int area;
  if( !bx_iodebug_s.enabled ) return;

  area = bx_iodebug_c::range_test( addr, len );
  // Device is enabled, testing address ranges
  if( area )
  {
    area--;
#if BX_DEBUGGER
    fprintf( stdout, "%s @ eip: %8X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
    bx_guard.interrupt_requested=1;
#else
    fprintf( stderr,
             "IODEBUG read to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     area,
	     cpu->get_EIP(),
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned int)addr);

    Bit32u data32 = * (Bit32u *)data;
    Bit16u data16 = (Bit16u)data32;
    Bit8u  data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%02X\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%04X\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%08X\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
{
  unsigned int i;

  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( (bx_iodebug_s.monitored_mem_areas_start[i]!=0) ||
        (bx_iodebug_s.monitored_mem_areas_end[i]!=0) )
    {
      if( (Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i] )
        continue;
      if( addr < bx_iodebug_s.monitored_mem_areas_end[i] )
      {
        return(++i);
      }
    }
  }
  return(0);
}

void bx_iodebug_c::add_range( Bit32u addr_start, Bit32u addr_end )
{
  unsigned int i;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( !bx_iodebug_s.monitored_mem_areas_start[i] &&
        !bx_iodebug_s.monitored_mem_areas_end[i] )
    {
	bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
	bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
//	fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
	return;
    }
  }
//  fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}

#endif /* if BX_SUPPORT_IODEBUG */
<commit_msg>Fix get_EIP references in iodebug<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: iodebug.cc,v 1.19 2005/11/29 17:38:57 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////

#include "iodev.h"
#if BX_SUPPORT_IODEBUG

bx_iodebug_c bx_iodebug;
bx_iodebug_c *bx_iodebug_ptr;

  struct bx_iodebug_s_type {
    bx_bool enabled;
    unsigned int register_select;
    Bit32u registers[2];
    Bit32u monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
    Bit32u monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
  } bx_iodebug_s;

// Constructor
bx_iodebug_c::bx_iodebug_c( void )
{
  put("IODEBUG");
  settype(IODEBUGLOG);

}

// Destructor
bx_iodebug_c::~bx_iodebug_c( void )
{
}

void bx_iodebug_c::init(void)
{
  int i;

  DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 7);
  DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 7);
  DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 7);
//  fprintf( stderr, "IODEBUG initialized\n");

  bx_iodebug_s.enabled = 0;
  bx_iodebug_s.register_select = 0;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
  }
}

void bx_iodebug_c::reset(unsigned type)
{
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  return( bx_iodebug_ptr->read(addr, io_len) );
}

Bit32u bx_iodebug_c::read( Bit32u addr, unsigned io_len )
{
  if(bx_iodebug_s.enabled) return(0x8A00);
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
  class_ptr->write( addr, dvalue, io_len );
}

void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
{
//  fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);

  if( addr == 0x8A01 && io_len == 2 )
  {
      bx_iodebug_s.registers[bx_iodebug_s.register_select] =
        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
	(dvalue & 0x0000FFFF );
  }

  if( (addr != 0x8A00) || (io_len != 2) ) return;

  if( !bx_iodebug_s.enabled )
  {
    if( dvalue == 0x8A00 )
    {
      bx_iodebug_s.enabled = 1;
//      fprintf(stderr, "IODEBUG enabled\n");
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
    }
    return;
  }

  switch( dvalue )
  {
    case( 0x8A01 ):
      bx_iodebug_s.register_select = 0;
//      fprintf( stderr, "IODEBUG register 0 selected\n");
      break;

    case( 0x8A02 ):
      bx_iodebug_s.register_select = 1;
//      fprintf( stderr, "IODEBUG register 1 selected\n");
      break;

    case( 0x8A80 ):
      bx_iodebug_s.register_select = 0;
      bx_iodebug_c::add_range(
          bx_iodebug_s.registers[0],
	  bx_iodebug_s.registers[1]);
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
      break;

#if BX_DEBUGGER
    case( 0x8AE0 ):
      fprintf( stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
      bx_guard.interrupt_requested=1;
      break;

    case( 0x8AE2):
      fprintf( stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
      BX_CPU(dbg_cpu)->trace = 0;
      break;

    case( 0x8AE3 ):
      fprintf( stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
      BX_CPU(dbg_cpu)->trace = 1;
      break;

    case( 0x8AE4 ):
      fprintf( stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
      BX_CPU(dbg_cpu)->trace_reg = 0;
      break;

    case( 0x8AE5 ):
      fprintf( stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
      BX_CPU(dbg_cpu)->trace_reg = 1;
      break;

#endif

    case( 0x8AFF ):
      bx_iodebug_s.enabled = 0;
//      fprintf( stderr, "IODEBUG device deactivated\n");
//      break;

//    default:
//      fprintf(stderr,"IODEBUG unsupported register code\n");
  }
}

// Static function
void bx_iodebug_c::mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  unsigned int area;
  if( !bx_iodebug_s.enabled ) return;

  area = bx_iodebug_c::range_test( addr, len );
  // Device is enabled, testing address ranges
  if( area )
  {
    area--;
#if BX_DEBUGGER
    fprintf( stdout, "%s @ eip: " FMT_ADDRX " wrote at monitored memory location %8X\n", cpu->name, cpu->get_ip(), addr);
    bx_guard.interrupt_requested=1;
#else
    fprintf( stderr,
             "IODEBUG write to monitored memory area: %2i\tby EIP:\t\t" FMT_ADDRX "\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     area,
	     cpu->get_ip(),
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned int)addr);

    Bit32u data32 = * (Bit32u *)data;
    Bit16u data16 = (Bit16u)data32;
    Bit8u  data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%02X\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%04X\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%08X\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
{
  unsigned int area;
  if( !bx_iodebug_s.enabled ) return;

  area = bx_iodebug_c::range_test( addr, len );
  // Device is enabled, testing address ranges
  if( area )
  {
    area--;
#if BX_DEBUGGER
    fprintf( stdout, "%s @ eip: " FMT_ADDRX " wrote at monitored memory location %8X\n", cpu->name, cpu->get_ip(), addr);
    bx_guard.interrupt_requested=1;
#else
    fprintf( stderr,
             "IODEBUG read to monitored memory area: %2i\tby EIP:\t\t" FMT_ADDRX "\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     area,
	     cpu->get_ip(),
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned int)addr);

    Bit32u data32 = * (Bit32u *)data;
    Bit16u data16 = (Bit16u)data32;
    Bit8u  data8  = (Bit8u)data32;

    switch(len)
    {
      case(1):
        fprintf(stderr,"%02X\n", (unsigned int)data8);
	break;

      case(2):
        fprintf(stderr,"%04X\n", (unsigned int)data16);
	break;

      case(4):
        fprintf(stderr,"%08X\n", (unsigned int)data32);
	break;

      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
{
  unsigned int i;

  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( (bx_iodebug_s.monitored_mem_areas_start[i]!=0) ||
        (bx_iodebug_s.monitored_mem_areas_end[i]!=0) )
    {
      if( (Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i] )
        continue;
      if( addr < bx_iodebug_s.monitored_mem_areas_end[i] )
      {
        return(++i);
      }
    }
  }
  return(0);
}

void bx_iodebug_c::add_range( Bit32u addr_start, Bit32u addr_end )
{
  unsigned int i;
  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if( !bx_iodebug_s.monitored_mem_areas_start[i] &&
        !bx_iodebug_s.monitored_mem_areas_end[i] )
    {
	bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
	bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
//	fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
	return;
    }
  }
//  fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}

#endif /* if BX_SUPPORT_IODEBUG */
<|endoftext|>


<commit_before><commit_msg>coverity#704703 Dereference after null check<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textToPronounce_zh.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 04:49:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// prevent internal compiler error with MSVC6SP3
#include <utility>

#include <rtl/string.hxx>
#include <rtl/ustrbuf.hxx>
#define TRANSLITERATION_ALL
#include <textToPronounce_zh.hxx>

using namespace com::sun::star::uno;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

sal_Int16 SAL_CALL TextToPronounce_zh::getType() throw (RuntimeException)
{
    return TransliterationType::ONE_TO_ONE| TransliterationType::IGNORE;
}

const sal_Unicode* SAL_CALL
TextToPronounce_zh::getPronounce(const sal_Unicode ch)
{
    static const sal_Unicode emptyString[]={0};
    if (idx) {
        sal_uInt16 address = idx[0][ch>>8];
        if (address != 0xFFFF)
            return &idx[2][idx[1][address + (ch & 0xFF)]];
    }
    return emptyString;
}

OUString SAL_CALL
TextToPronounce_zh::folding(const OUString & inStr, sal_Int32 startPos,
        sal_Int32 nCount, Sequence< sal_Int32 > & offset) throw (RuntimeException)
{
    OUStringBuffer sb;
    const sal_Unicode * chArr = inStr.getStr() + startPos;

    if (startPos < 0)
        throw RuntimeException();

    if (startPos + nCount > inStr.getLength())
        nCount = inStr.getLength() - startPos;

    offset[0] = 0;
    for (sal_Int32 i = 0; i < nCount; i++) {
        OUString pron(getPronounce(chArr[i]));
        sb.append(pron);

        if (useOffset)
            offset[i + 1] = offset[i] + pron.getLength();
    }
    return sb.makeStringAndClear();
}

OUString SAL_CALL
TextToPronounce_zh::transliterateChar2String( sal_Unicode inChar) throw(RuntimeException)
{
    return OUString(getPronounce(inChar));
}

sal_Unicode SAL_CALL
TextToPronounce_zh::transliterateChar2Char( sal_Unicode inChar) throw(RuntimeException, MultipleCharsOutputException)
{
    const sal_Unicode* pron=getPronounce(inChar);
    if (!pron || !pron[0])
        return 0;
    if (pron[1])
        throw MultipleCharsOutputException();
    return *pron;
}

sal_Bool SAL_CALL
TextToPronounce_zh::equals( const OUString & str1, sal_Int32 pos1, sal_Int32 nCount1, sal_Int32 & nMatch1,
        const OUString & str2, sal_Int32 pos2, sal_Int32 nCount2, sal_Int32 & nMatch2)
        throw (RuntimeException)
{
    sal_Int32 realCount;
    int i;  // loop variable
    const sal_Unicode * s1, * s2;
    const sal_Unicode *pron1, *pron2;

    if (nCount1 + pos1 > str1.getLength())
        nCount1 = str1.getLength() - pos1;

    if (nCount2 + pos2 > str2.getLength())
        nCount2 = str2.getLength() - pos2;

    realCount = ((nCount1 > nCount2) ? nCount2 : nCount1);

    s1 = str1.getStr() + pos1;
    s2 = str2.getStr() + pos2;
    for (i = 0; i < realCount; i++) {
        pron1=getPronounce(*s1++);
        pron2=getPronounce(*s2++);
        if (pron1 != pron2) {
            nMatch1 = nMatch2 = i;
            return sal_False;
        }
    }
    nMatch1 = nMatch2 = realCount;
    return (nCount1 == nCount2);
}

TextToPinyin_zh_CN::TextToPinyin_zh_CN() : TextToPronounce_zh("get_zh_pinyin")
{
        transliterationName = "ChineseCharacterToPinyin";
        implementationName = "com.sun.star.i18n.Transliteration.TextToPinyin_zh_CN";
}

TextToChuyin_zh_TW::TextToChuyin_zh_TW() : TextToPronounce_zh("get_zh_zhuyin")
{
        transliterationName = "ChineseCharacterToChuyin";
        implementationName = "com.sun.star.i18n.Transliteration.TextToChuyin_zh_TW";
}

TextToPronounce_zh::TextToPronounce_zh(const sal_Char* func_name)
{
#ifdef SAL_DLLPREFIX
    OUString lib=OUString::createFromAscii(SAL_DLLPREFIX"index_data"SAL_DLLEXTENSION);
#else
    OUString lib=OUString::createFromAscii("index_data"SAL_DLLEXTENSION);
#endif
    hModule = osl_loadModule( lib.pData, SAL_LOADMODULE_DEFAULT );
    idx=NULL;
    if (hModule) {
        sal_uInt16** (*function)() = (sal_uInt16** (*)()) osl_getFunctionSymbol(hModule, OUString::createFromAscii(func_name).pData);
        if (function)
            idx=function();
    }
}
TextToPronounce_zh::~TextToPronounce_zh()
{
    if (hModule) osl_unloadModule(hModule);
}
} } } }
<commit_msg>INTEGRATION: CWS pchfix02 (1.10.16); FILE MERGED 2006/09/01 17:30:54 kaib 1.10.16.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textToPronounce_zh.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 09:31:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_i18npool.hxx"

// prevent internal compiler error with MSVC6SP3
#include <utility>

#include <rtl/string.hxx>
#include <rtl/ustrbuf.hxx>
#define TRANSLITERATION_ALL
#include <textToPronounce_zh.hxx>

using namespace com::sun::star::uno;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

sal_Int16 SAL_CALL TextToPronounce_zh::getType() throw (RuntimeException)
{
    return TransliterationType::ONE_TO_ONE| TransliterationType::IGNORE;
}

const sal_Unicode* SAL_CALL
TextToPronounce_zh::getPronounce(const sal_Unicode ch)
{
    static const sal_Unicode emptyString[]={0};
    if (idx) {
        sal_uInt16 address = idx[0][ch>>8];
        if (address != 0xFFFF)
            return &idx[2][idx[1][address + (ch & 0xFF)]];
    }
    return emptyString;
}

OUString SAL_CALL
TextToPronounce_zh::folding(const OUString & inStr, sal_Int32 startPos,
        sal_Int32 nCount, Sequence< sal_Int32 > & offset) throw (RuntimeException)
{
    OUStringBuffer sb;
    const sal_Unicode * chArr = inStr.getStr() + startPos;

    if (startPos < 0)
        throw RuntimeException();

    if (startPos + nCount > inStr.getLength())
        nCount = inStr.getLength() - startPos;

    offset[0] = 0;
    for (sal_Int32 i = 0; i < nCount; i++) {
        OUString pron(getPronounce(chArr[i]));
        sb.append(pron);

        if (useOffset)
            offset[i + 1] = offset[i] + pron.getLength();
    }
    return sb.makeStringAndClear();
}

OUString SAL_CALL
TextToPronounce_zh::transliterateChar2String( sal_Unicode inChar) throw(RuntimeException)
{
    return OUString(getPronounce(inChar));
}

sal_Unicode SAL_CALL
TextToPronounce_zh::transliterateChar2Char( sal_Unicode inChar) throw(RuntimeException, MultipleCharsOutputException)
{
    const sal_Unicode* pron=getPronounce(inChar);
    if (!pron || !pron[0])
        return 0;
    if (pron[1])
        throw MultipleCharsOutputException();
    return *pron;
}

sal_Bool SAL_CALL
TextToPronounce_zh::equals( const OUString & str1, sal_Int32 pos1, sal_Int32 nCount1, sal_Int32 & nMatch1,
        const OUString & str2, sal_Int32 pos2, sal_Int32 nCount2, sal_Int32 & nMatch2)
        throw (RuntimeException)
{
    sal_Int32 realCount;
    int i;  // loop variable
    const sal_Unicode * s1, * s2;
    const sal_Unicode *pron1, *pron2;

    if (nCount1 + pos1 > str1.getLength())
        nCount1 = str1.getLength() - pos1;

    if (nCount2 + pos2 > str2.getLength())
        nCount2 = str2.getLength() - pos2;

    realCount = ((nCount1 > nCount2) ? nCount2 : nCount1);

    s1 = str1.getStr() + pos1;
    s2 = str2.getStr() + pos2;
    for (i = 0; i < realCount; i++) {
        pron1=getPronounce(*s1++);
        pron2=getPronounce(*s2++);
        if (pron1 != pron2) {
            nMatch1 = nMatch2 = i;
            return sal_False;
        }
    }
    nMatch1 = nMatch2 = realCount;
    return (nCount1 == nCount2);
}

TextToPinyin_zh_CN::TextToPinyin_zh_CN() : TextToPronounce_zh("get_zh_pinyin")
{
        transliterationName = "ChineseCharacterToPinyin";
        implementationName = "com.sun.star.i18n.Transliteration.TextToPinyin_zh_CN";
}

TextToChuyin_zh_TW::TextToChuyin_zh_TW() : TextToPronounce_zh("get_zh_zhuyin")
{
        transliterationName = "ChineseCharacterToChuyin";
        implementationName = "com.sun.star.i18n.Transliteration.TextToChuyin_zh_TW";
}

TextToPronounce_zh::TextToPronounce_zh(const sal_Char* func_name)
{
#ifdef SAL_DLLPREFIX
    OUString lib=OUString::createFromAscii(SAL_DLLPREFIX"index_data"SAL_DLLEXTENSION);
#else
    OUString lib=OUString::createFromAscii("index_data"SAL_DLLEXTENSION);
#endif
    hModule = osl_loadModule( lib.pData, SAL_LOADMODULE_DEFAULT );
    idx=NULL;
    if (hModule) {
        sal_uInt16** (*function)() = (sal_uInt16** (*)()) osl_getFunctionSymbol(hModule, OUString::createFromAscii(func_name).pData);
        if (function)
            idx=function();
    }
}
TextToPronounce_zh::~TextToPronounce_zh()
{
    if (hModule) osl_unloadModule(hModule);
}
} } } }
<|endoftext|>


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

#include "HTTPFileRequest.hxx"
#include <simgear/debug/logstream.hxx>

namespace simgear
{
namespace HTTP
{

  //----------------------------------------------------------------------------
  FileRequest::FileRequest(const std::string& url, const std::string& path):
    Request(url, "GET"),
    _filename(path)
  {

  }

  //----------------------------------------------------------------------------
  void FileRequest::responseHeadersComplete()
  {
    Request::responseHeadersComplete();

    if( !_filename.empty() )
      // TODO validate path? (would require to expose fgValidatePath somehow to
      //      simgear)
      _file.open(_filename.c_str(), std::ios::binary | std::ios::trunc);

    if( !_file )
    {
      SG_LOG
      (
        SG_IO,
        SG_WARN,
        "HTTP::FileRequest: failed to open file '" << _filename << "'"
      );

      abort("Failed to open file.");
    }
  }

  //----------------------------------------------------------------------------
  void FileRequest::gotBodyData(const char* s, int n)
  {
    if( !_file )
    {
      SG_LOG
      (
        SG_IO,
        SG_WARN,
        "HTTP::FileRequest: error writing to '" << _filename << "'"
      );
      return;
    }

    _file.write(s, n);
  }

  //----------------------------------------------------------------------------
  void FileRequest::onAlways()
  {
    _file.close();
  }

} // namespace HTTP
} // namespace simgear
<commit_msg>HTTPFileRequest: create directory if it does not exist<commit_after>// HTTP request writing response to a file.
//
// Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA

#include "HTTPFileRequest.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>

namespace simgear
{
namespace HTTP
{

  //----------------------------------------------------------------------------
  FileRequest::FileRequest(const std::string& url, const std::string& path):
    Request(url, "GET"),
    _filename(path)
  {

  }

  //----------------------------------------------------------------------------
  void FileRequest::responseHeadersComplete()
  {
    Request::responseHeadersComplete();

    if( !_filename.empty() )
    {
      // TODO validate path? (would require to expose fgValidatePath somehow to
      //      simgear)
      SGPath path(_filename);
      path.create_dir(0777);

      _file.open(_filename.c_str(), std::ios::binary | std::ios::trunc);
    }

    if( !_file )
    {
      SG_LOG
      (
        SG_IO,
        SG_WARN,
        "HTTP::FileRequest: failed to open file '" << _filename << "'"
      );

      abort("Failed to open file.");
    }
  }

  //----------------------------------------------------------------------------
  void FileRequest::gotBodyData(const char* s, int n)
  {
    if( !_file )
    {
      SG_LOG
      (
        SG_IO,
        SG_WARN,
        "HTTP::FileRequest: error writing to '" << _filename << "'"
      );
      return;
    }

    _file.write(s, n);
  }

  //----------------------------------------------------------------------------
  void FileRequest::onAlways()
  {
    _file.close();
  }

} // namespace HTTP
} // namespace simgear
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   SimpleTimer.cpp
    created:    Sat Feb 18 2012
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/SimpleTimer.h"

#if (defined(__WIN32__) || defined(_WIN32)) && (not defined __MINGW32__)
#include <windows.h>
double CEGUI::SimpleTimer::currentTime()
{
    return timeGetTime() / 1000.0;
}

#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(__CYGWIN__) || defined(__MINGW32__)
#include <sys/time.h>
double CEGUI::SimpleTimer::currentTime()
{
    timeval timeStructure;
    gettimeofday(&timeStructure, 0);
    return timeStructure.tv_sec + timeStructure.tv_usec / 1000000.0;
}
#else
#error "SimpleTimer not available for this platform, please implement it"
#endif
<commit_msg>FIX: Fixed directive in merged pull request<commit_after>/***********************************************************************
    filename:   SimpleTimer.cpp
    created:    Sat Feb 18 2012
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/SimpleTimer.h"

#if (defined(__WIN32__) || defined(_WIN32) ) && (!defined __MINGW32__)
#include <windows.h>
double CEGUI::SimpleTimer::currentTime()
{
    return timeGetTime() / 1000.0;
}

#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(__CYGWIN__) || defined(__MINGW32__)
#include <sys/time.h>
double CEGUI::SimpleTimer::currentTime()
{
    timeval timeStructure;
    gettimeofday(&timeStructure, 0);
    return timeStructure.tv_sec + timeStructure.tv_usec / 1000000.0;
}
#else
#error "SimpleTimer not available for this platform, please implement it"
#endif
<|endoftext|>


<commit_before>/***********************************************************************
	filename: 	UndoHandler.cpp
	created:	15/07/2013
	author:		Erihel

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

// Start of CEGUI namespace section
namespace CEGUI
{

//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////
UndoHandler::UndoHandler(Window *window) :
    d_undoLimit(10),
    d_undoPosition(-1),
    d_lastUndo(true)
{
    d_attachedWindow = window;
}

/*************************************************************************
    Undo/Redo
*************************************************************************/
bool UndoHandler::undo(size_t &cursor)
{
    if (!d_attachedWindow)
        return false;

    if (canUndo())
    {
        if (d_undoPosition < d_undoList.size())
        {
            UndoAction &action = d_undoList[d_undoPosition--];

            String newText = d_attachedWindow->getText();
            if (action.d_type == UAT_INSERT)
            {
                newText.erase(action.d_startIdx, action.d_text.length());
                cursor = action.d_startIdx;
            }
            else
            {
                newText.insert(action.d_startIdx, action.d_text);
                cursor = action.d_startIdx + action.d_text.length();
            }
            d_attachedWindow->setText(newText);
            d_lastUndo = true;
            return true;
        }
    }
    return false;
}

//----------------------------------------------------------------------------//
bool UndoHandler::redo(size_t &cursor)
{
    if (!d_attachedWindow)
        return false;

    if (canRedo())
    {
        UndoAction &action = d_undoList[++d_undoPosition];

        String newText = d_attachedWindow->getText();
        if (action.d_type == UAT_INSERT)
        {
            newText.insert(action.d_startIdx, action.d_text);
            cursor = action.d_startIdx + action.d_text.length();
        }
        else
        {
            newText.erase(action.d_startIdx, action.d_text.length());
            cursor = action.d_startIdx;
        }
        d_attachedWindow->setText(newText);
        d_lastUndo = false;
        return true;
    }
    return false;
}

//----------------------------------------------------------------------------//
void UndoHandler::setUndoLimit(int limit)
{
    if (limit < 0)
    {
        CEGUI_THROW(InvalidRequestException("Invalid undo limit. Limit cannot be less then zero."));
    }

    d_undoLimit = limit;

    while (d_undoList.size() > d_undoLimit)
        d_undoList.pop_front();

    d_undoPosition = d_undoList.size() - 1;
}

//----------------------------------------------------------------------------//
void UndoHandler::addUndoHistory(UndoAction &action)
{
    // discard all actions that are after our current position in undo list
    while (d_undoList.size() > 0 && d_undoPosition < static_cast<int>(d_undoList.size()) - 1)
        d_undoList.pop_back();

    if (d_undoList.size() > d_undoLimit)
        d_undoList.pop_front();

    d_undoList.push_back(action);
    d_undoPosition = d_undoList.size() - 1;
}

//----------------------------------------------------------------------------//
void UndoHandler::clearUndoHistory()
{
    d_undoList.clear();
    d_undoPosition = -1;
}

//----------------------------------------------------------------------------//
size_t UndoHandler::count()
{
    return d_undoList.size();
}

//----------------------------------------------------------------------------//
bool UndoHandler::canUndo()
{
    return (d_undoList.size() > 0 && d_undoPosition >= 0);
}

//----------------------------------------------------------------------------//
bool UndoHandler::canRedo()
{
    return (d_undoList.size() > 0 && d_undoPosition < static_cast<int>(d_undoList.size()) - 1);
}

//----------------------------------------------------------------------------//
UndoHandler::UndoAction UndoHandler::getLastAction()
{
    UndoAction lastAction;

    if (d_lastUndo)
    {
        if (d_undoPosition == d_undoList.size() - 1)
            lastAction = d_undoList[d_undoPosition];
        else
            lastAction = d_undoList[d_undoPosition + 1];
    }
    else
    {
        if (d_undoPosition <= 0)
            lastAction = d_undoList[0];
        else
            lastAction = d_undoList[d_undoPosition];
    }
    return lastAction;
}

} // End of  CEGUI namespace section

<commit_msg>MOD: Removed warning<commit_after>/***********************************************************************
	filename: 	UndoHandler.cpp
	created:	15/07/2013
	author:		Erihel

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

// Start of CEGUI namespace section
namespace CEGUI
{

//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////
UndoHandler::UndoHandler(Window *window) :
    d_undoLimit(10),
    d_undoPosition(-1),
    d_lastUndo(true)
{
    d_attachedWindow = window;
}

/*************************************************************************
    Undo/Redo
*************************************************************************/
bool UndoHandler::undo(size_t &cursor)
{
    if (!d_attachedWindow)
        return false;

    if (canUndo())
    {
        if (static_cast<size_t>(d_undoPosition) < d_undoList.size())
        {
            UndoAction &action = d_undoList[d_undoPosition--];

            String newText = d_attachedWindow->getText();
            if (action.d_type == UAT_INSERT)
            {
                newText.erase(action.d_startIdx, action.d_text.length());
                cursor = action.d_startIdx;
            }
            else
            {
                newText.insert(action.d_startIdx, action.d_text);
                cursor = action.d_startIdx + action.d_text.length();
            }
            d_attachedWindow->setText(newText);
            d_lastUndo = true;
            return true;
        }
    }
    return false;
}

//----------------------------------------------------------------------------//
bool UndoHandler::redo(size_t &cursor)
{
    if (!d_attachedWindow)
        return false;

    if (canRedo())
    {
        UndoAction &action = d_undoList[++d_undoPosition];

        String newText = d_attachedWindow->getText();
        if (action.d_type == UAT_INSERT)
        {
            newText.insert(action.d_startIdx, action.d_text);
            cursor = action.d_startIdx + action.d_text.length();
        }
        else
        {
            newText.erase(action.d_startIdx, action.d_text.length());
            cursor = action.d_startIdx;
        }
        d_attachedWindow->setText(newText);
        d_lastUndo = false;
        return true;
    }
    return false;
}

//----------------------------------------------------------------------------//
void UndoHandler::setUndoLimit(int limit)
{
    if (limit < 0)
    {
        CEGUI_THROW(InvalidRequestException("Invalid undo limit. Limit cannot be less then zero."));
    }

    d_undoLimit = limit;

    while (d_undoList.size() > d_undoLimit)
        d_undoList.pop_front();

    d_undoPosition = d_undoList.size() - 1;
}

//----------------------------------------------------------------------------//
void UndoHandler::addUndoHistory(UndoAction &action)
{
    // discard all actions that are after our current position in undo list
    while (d_undoList.size() > 0 && d_undoPosition < static_cast<int>(d_undoList.size()) - 1)
        d_undoList.pop_back();

    if (d_undoList.size() > d_undoLimit)
        d_undoList.pop_front();

    d_undoList.push_back(action);
    d_undoPosition = d_undoList.size() - 1;
}

//----------------------------------------------------------------------------//
void UndoHandler::clearUndoHistory()
{
    d_undoList.clear();
    d_undoPosition = -1;
}

//----------------------------------------------------------------------------//
size_t UndoHandler::count()
{
    return d_undoList.size();
}

//----------------------------------------------------------------------------//
bool UndoHandler::canUndo()
{
    return (d_undoList.size() > 0 && d_undoPosition >= 0);
}

//----------------------------------------------------------------------------//
bool UndoHandler::canRedo()
{
    return (d_undoList.size() > 0 && d_undoPosition < static_cast<int>(d_undoList.size()) - 1);
}

//----------------------------------------------------------------------------//
UndoHandler::UndoAction UndoHandler::getLastAction()
{
    UndoAction lastAction;

    if (d_lastUndo)
    {
        if (d_undoPosition == d_undoList.size() - 1)
            lastAction = d_undoList[d_undoPosition];
        else
            lastAction = d_undoList[d_undoPosition + 1];
    }
    else
    {
        if (d_undoPosition <= 0)
            lastAction = d_undoList[0];
        else
            lastAction = d_undoList[d_undoPosition];
    }
    return lastAction;
}

} // End of  CEGUI namespace section

<|endoftext|>