<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * Licensed under the MIT license (see LICENSE).
 */
#include <stdlib.h>
#include <assert.h>
#include "barchart.h"
#include "canvas.h"
#include "domain.h"
#include "rendertarget.h"

/**
 * todo:
 *  - labels inside/outside
 */
namespace fnordmetric {
namespace ui {

BarChart::BarChart(
    Canvas* canvas,
    kBarChartOrientation orientation /* = O_HORIZONTAL */,
    NumericalDomain* y_domain /* = nullptr */) :
    canvas_(canvas),
    orientation_(orientation),
    y_domain_(y_domain),
    num_series_(0) {}

void BarChart::addSeries(Series2D<std::string, double>* series) {
  for (const auto& point : series->getData()) {
    const auto& x_val = std::get<0>(point);
    const auto& y_val = std::get<1>(point);

    BarData* bar_data = nullptr;

    for (auto& candidate : data_) {
      if (candidate.x == x_val) {
        bar_data = &candidate;
      }
    }

    if (bar_data == nullptr) {
      data_.emplace_back();
      bar_data = &data_.back();
      bar_data->x = x_val;
    }

    bar_data->ys.emplace_back(0, y_val);   //scaleValue(&y_val, &y_domain));
  }

  num_series_++;
}

AxisDefinition* BarChart::addAxis(AxisDefinition::kPosition position) {
  switch (position) {

    case AxisDefinition::TOP:
      switch (orientation_) {
        case O_VERTICAL:
          return newLabelAxis(position);
          break;
        case O_HORIZONTAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
      }
      break;

    case AxisDefinition::RIGHT:
      switch (orientation_) {
        case O_VERTICAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
        case O_HORIZONTAL:
          return newLabelAxis(position);
          break;
      }
      break;

    case AxisDefinition::BOTTOM:
      switch (orientation_) {
        case O_VERTICAL:
          return newLabelAxis(position);
          break;
        case O_HORIZONTAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
      }
      break;

    case AxisDefinition::LEFT:
      switch (orientation_) {
        case O_VERTICAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
        case O_HORIZONTAL:
          return newLabelAxis(position);
          break;
      }
      break;

  }
}

void BarChart::render(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  switch (orientation_) {
    case O_VERTICAL:
      renderVerticalBars(target, width, height, padding);
      break;
    case O_HORIZONTAL:
      renderHorizontalBars(target, width, height, padding);
      break;
  }
}

void BarChart::renderVerticalBars(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  /* calculate bar width and padding */
  auto padding_top = std::get<0>(*padding);
  auto padding_right = std::get<1>(*padding);
  auto padding_bottom = std::get<2>(*padding);
  auto padding_left = std::get<3>(*padding);
  auto inner_width = width - padding_right - padding_left;
  auto inner_height = height - padding_top - padding_bottom;
  auto bar_width = (inner_width / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (inner_width / data_.size()) * (kBarPadding * 0.5f);
  bar_width -= bar_padding / data_.size() * 2;

  /* draw the bars */
  std::vector<double> x_ticks = {0.0f};
  auto draw_x = padding_left + bar_padding;
  auto draw_width = bar_width;
  auto y_domain = getValueDomain();
  for (const auto& bar : data_) {
    draw_x += bar_padding;

    /* single series */
    if (num_series_ == 1) {
      auto y_min = y_domain->scale(bar.ys[0].first);
      auto y_max = y_domain->scale(bar.ys[0].second);
      auto draw_y = padding_top + ((1.0f - y_max) * inner_height);
      auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height;
      target->drawRect(draw_x, draw_y, draw_width, draw_height, "color0");
    }

    /* multi series stacked */
    /*else if (stacked_) {
      double y_min = 0.0f;
      double y_max = 0.0f;
      for (int i = 0; i < bar.ys.size(); i++) {
        auto& y_val = bar.ys[i];
        y_max += y_val.second - y_val.first;
        auto draw_y = padding_top_ + ((1.0f - y_max) * inner_height_);
        auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height_;
        target->drawRect(draw_x, draw_y, draw_width, draw_height, colorName(i));
        y_min += y_val.second - y_val.first;
      }
    }*/

    /* multi series unstacked */
    else {
      auto draw_x_multi = draw_x;
      auto draw_width_multi = draw_width / (double) num_series_;
      for (int i = 0; i < bar.ys.size(); i++) {
      auto y_min = y_domain->scale(bar.ys[i].first);
      auto y_max = y_domain->scale(bar.ys[i].second);
        auto draw_y = padding_top + ((1.0f - y_max) * inner_height);
        auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height;
        target->drawRect(
            draw_x_multi,
            draw_y,
            draw_width_multi * (1.0f - kBarPadding * 0.5f),
            draw_height,
            "color0");
        draw_x_multi += (draw_width_multi * (1.0f + kBarPadding * 0.5f));
      }
    }

    draw_x += bar_width + bar_padding;
  }
}
void BarChart::renderHorizontalBars(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  /* calculate bar width and padding */
  auto padding_top = std::get<0>(*padding);
  auto padding_right = std::get<1>(*padding);
  auto padding_bottom = std::get<2>(*padding);
  auto padding_left = std::get<3>(*padding);
  auto inner_width = width - padding_right - padding_left;
  auto inner_height = height - padding_top - padding_bottom;
  auto bar_height = (inner_height / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (inner_height / data_.size()) * (kBarPadding * 0.5f);
  bar_height -= bar_padding / data_.size() * 2;

  /* draw the bars */
  std::vector<double> y_ticks = {0.0f};
  std::vector<std::pair<double, std::string>> y_labels;
  auto draw_y = padding_top + bar_padding;
  auto draw_height = bar_height;
  auto y_domain = getValueDomain();
  for (const auto& bar : data_) {
    draw_y += bar_padding;

    /* single series */
    if (num_series_ == 1) {
      auto& y_val = bar.ys[0];
      auto y_min = y_domain->scale(bar.ys[0].first);
      auto y_max = y_domain->scale(bar.ys[0].second);
      auto draw_x = padding_left + y_min * inner_width;
      auto draw_width = (y_max - y_min) * inner_width;
      target->drawRect(draw_x, draw_y, draw_width, draw_height, "color0");
    }

    /* multi series stacked */
    /*else if (stacked_) {
      double y_min = 0.0f;
      double y_max = 0.0f;
      for (int i = 0; i < bar.ys.size(); i++) {
        auto& y_val = bar.ys[i];
        y_max += y_val.second - y_val.first;
        auto draw_x = padding_left_ + y_min * inner_width_;
        auto draw_width = (y_max - y_min) * inner_width_;
        target->drawRect(draw_x, draw_y, draw_width, draw_height, colorName(i));
        y_min += y_val.second - y_val.first;
      }
    }*/

    /* multi series unstacked */
    else {
      /*
      auto num_series = getSeries().size();
      auto draw_y_multi = draw_y;
      auto draw_height_multi = draw_height / num_series;
      for (int i = 0; i < bar.ys.size(); i++) {
        auto& y_val = bar.ys[i];
        auto y_min = y_val.first;
        auto y_max = y_val.second;
        auto draw_x = padding_left_ + y_min * inner_width_;
        auto draw_width = (y_max - y_min) * inner_width_;
        target->drawRect(
            draw_x,
            draw_y_multi,
            draw_width,
            draw_height_multi * (1.0f - kBarPadding * 0.5f),
            colorName(i));
        draw_y_multi += (draw_height_multi * (1.0f + kBarPadding * 0.5f));
      }
      */
    }

    draw_y += bar_height + bar_padding;
  }
}

NumericalDomain* BarChart::getValueDomain() const {
  if (y_domain_ != nullptr) {
    return y_domain_;
  }

  if (y_domain_auto_.get() == nullptr) {
    y_domain_auto_.reset(newValueDomain());
  }

  return y_domain_auto_.get();
}

NumericalDomain* BarChart::newValueDomain() const {
  /* calculate our domain*/
  if (stacked_) {
    /*
    int num_bars = 0;
    for (const auto& series : getSeries()) {
      if (series->getData().size() > num_bars) {
        num_bars = series->getData().size();
      }
    }

    double y_domain_max = 0.0f;
    for (int i = 0; i < num_bars; ++i) {
      int sum = 0;
      for (const auto& series : getSeries()) {
        if (i < series->getData().size()) {
          sum += series->getData()[i][1].getFloat();
        }
      }

      if (sum > y_domain_max) {
        y_domain_max = sum;
      }
    }
    y_domain = Domain(0, y_domain_max, false);
    */
  } else {
    double y_domain_min = 0.0f;
    double y_domain_max = 0.0f;

    for (const auto& group : data_) {
      for (const auto& y : group.ys) {
        if (y.first < y_domain_min) {
          y_domain_min = y.first;
        }
        if (y.first > y_domain_max) {
          y_domain_max = y.first;
        }
        if (y.second < y_domain_min) {
          y_domain_min = y.second;
        }
        if (y.second > y_domain_max) {
          y_domain_max = y.second;
        }
      }
    }

    if (y_domain_max > 0) {
      y_domain_max *= 1.1;
    }

    return new NumericalDomain(y_domain_min, y_domain_max, false);
  }
}

AxisDefinition* BarChart::newLabelAxis(AxisDefinition::kPosition position)
    const {
  auto axis = canvas_->addAxis(position);
  axis->addTick(0.0f);

  auto bar_width = (1.0 / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (1.0 / data_.size()) * (kBarPadding * 0.5f);
  bar_width -= bar_padding / data_.size() * 2;

  auto draw_x = bar_padding;
  for (int i = 0; i < data_.size(); ++i) {
    draw_x += bar_padding;

    switch (orientation_) {
      case O_VERTICAL:
        axis->addLabel(draw_x + bar_width * 0.5f, data_[i].x);
        break;
      case O_HORIZONTAL:
        axis->addLabel(
            draw_x + bar_width * 0.5f,
            data_[data_.size() - 1 - i].x);
        break;
    }

    draw_x += bar_width + bar_padding;
    if (i < data_.size() - 1) {
      axis->addTick(draw_x);
    }
  }

  axis->addTick(1.0f);
  return axis;
}

}
}
<commit_msg>draw multiseries horizontal bars<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * Licensed under the MIT license (see LICENSE).
 */
#include <stdlib.h>
#include <assert.h>
#include "barchart.h"
#include "canvas.h"
#include "domain.h"
#include "rendertarget.h"

/**
 * todo:
 *  - labels inside/outside
 */
namespace fnordmetric {
namespace ui {

BarChart::BarChart(
    Canvas* canvas,
    kBarChartOrientation orientation /* = O_HORIZONTAL */,
    NumericalDomain* y_domain /* = nullptr */) :
    canvas_(canvas),
    orientation_(orientation),
    y_domain_(y_domain),
    num_series_(0) {}

void BarChart::addSeries(Series2D<std::string, double>* series) {
  for (const auto& point : series->getData()) {
    const auto& x_val = std::get<0>(point);
    const auto& y_val = std::get<1>(point);

    BarData* bar_data = nullptr;

    for (auto& candidate : data_) {
      if (candidate.x == x_val) {
        bar_data = &candidate;
      }
    }

    if (bar_data == nullptr) {
      data_.emplace_back();
      bar_data = &data_.back();
      bar_data->x = x_val;
    }

    bar_data->ys.emplace_back(0, y_val);   //scaleValue(&y_val, &y_domain));
  }

  num_series_++;
}

AxisDefinition* BarChart::addAxis(AxisDefinition::kPosition position) {
  switch (position) {

    case AxisDefinition::TOP:
      switch (orientation_) {
        case O_VERTICAL:
          return newLabelAxis(position);
          break;
        case O_HORIZONTAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
      }
      break;

    case AxisDefinition::RIGHT:
      switch (orientation_) {
        case O_VERTICAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
        case O_HORIZONTAL:
          return newLabelAxis(position);
          break;
      }
      break;

    case AxisDefinition::BOTTOM:
      switch (orientation_) {
        case O_VERTICAL:
          return newLabelAxis(position);
          break;
        case O_HORIZONTAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
      }
      break;

    case AxisDefinition::LEFT:
      switch (orientation_) {
        case O_VERTICAL:
          return canvas_->addAxis(position, getValueDomain());
          break;
        case O_HORIZONTAL:
          return newLabelAxis(position);
          break;
      }
      break;

  }
}

void BarChart::render(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  switch (orientation_) {
    case O_VERTICAL:
      renderVerticalBars(target, width, height, padding);
      break;
    case O_HORIZONTAL:
      renderHorizontalBars(target, width, height, padding);
      break;
  }
}

void BarChart::renderVerticalBars(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  /* calculate bar width and padding */
  auto padding_top = std::get<0>(*padding);
  auto padding_right = std::get<1>(*padding);
  auto padding_bottom = std::get<2>(*padding);
  auto padding_left = std::get<3>(*padding);
  auto inner_width = width - padding_right - padding_left;
  auto inner_height = height - padding_top - padding_bottom;
  auto bar_width = (inner_width / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (inner_width / data_.size()) * (kBarPadding * 0.5f);
  bar_width -= bar_padding / data_.size() * 2;

  /* draw the bars */
  std::vector<double> x_ticks = {0.0f};
  auto draw_x = padding_left + bar_padding;
  auto draw_width = bar_width;
  auto y_domain = getValueDomain();
  for (const auto& bar : data_) {
    draw_x += bar_padding;

    /* single series */
    if (num_series_ == 1) {
      auto y_min = y_domain->scale(bar.ys[0].first);
      auto y_max = y_domain->scale(bar.ys[0].second);
      auto draw_y = padding_top + ((1.0f - y_max) * inner_height);
      auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height;
      target->drawRect(draw_x, draw_y, draw_width, draw_height, "color0");
    }

    /* multi series stacked */
    /*else if (stacked_) {
      double y_min = 0.0f;
      double y_max = 0.0f;
      for (int i = 0; i < bar.ys.size(); i++) {
        auto& y_val = bar.ys[i];
        y_max += y_val.second - y_val.first;
        auto draw_y = padding_top_ + ((1.0f - y_max) * inner_height_);
        auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height_;
        target->drawRect(draw_x, draw_y, draw_width, draw_height, colorName(i));
        y_min += y_val.second - y_val.first;
      }
    }*/

    /* multi series unstacked */
    else {
      auto draw_x_multi = draw_x;
      auto draw_width_multi = draw_width / (double) num_series_;
      for (int i = 0; i < bar.ys.size(); i++) {
      auto y_min = y_domain->scale(bar.ys[i].first);
      auto y_max = y_domain->scale(bar.ys[i].second);
        auto draw_y = padding_top + ((1.0f - y_max) * inner_height);
        auto draw_height = (1.0f - ((1.0f - y_max) + y_min)) * inner_height;
        target->drawRect(
            draw_x_multi,
            draw_y,
            draw_width_multi * (1.0f - kBarPadding * 0.5f),
            draw_height,
            "color0");
        draw_x_multi += (draw_width_multi * (1.0f + kBarPadding * 0.5f));
      }
    }

    draw_x += bar_width + bar_padding;
  }
}
void BarChart::renderHorizontalBars(
    RenderTarget* target,
    int width,
    int height,
    std::tuple<int, int, int, int>* padding) const {
  /* calculate bar width and padding */
  auto padding_top = std::get<0>(*padding);
  auto padding_right = std::get<1>(*padding);
  auto padding_bottom = std::get<2>(*padding);
  auto padding_left = std::get<3>(*padding);
  auto inner_width = width - padding_right - padding_left;
  auto inner_height = height - padding_top - padding_bottom;
  auto bar_height = (inner_height / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (inner_height / data_.size()) * (kBarPadding * 0.5f);
  bar_height -= bar_padding / data_.size() * 2;

  /* draw the bars */
  std::vector<double> y_ticks = {0.0f};
  std::vector<std::pair<double, std::string>> y_labels;
  auto draw_y = padding_top + bar_padding;
  auto draw_height = bar_height;
  auto y_domain = getValueDomain();
  for (const auto& bar : data_) {
    draw_y += bar_padding;

    /* single series */
    if (num_series_ == 1) {
      auto& y_val = bar.ys[0];
      auto y_min = y_domain->scale(bar.ys[0].first);
      auto y_max = y_domain->scale(bar.ys[0].second);
      auto draw_x = padding_left + y_min * inner_width;
      auto draw_width = (y_max - y_min) * inner_width;
      target->drawRect(draw_x, draw_y, draw_width, draw_height, "color0");
    }

    /* multi series stacked */
    /*else if (stacked_) {
      double y_min = 0.0f;
      double y_max = 0.0f;
      for (int i = 0; i < bar.ys.size(); i++) {
        auto& y_val = bar.ys[i];
        y_max += y_val.second - y_val.first;
        auto draw_x = padding_left_ + y_min * inner_width_;
        auto draw_width = (y_max - y_min) * inner_width_;
        target->drawRect(draw_x, draw_y, draw_width, draw_height, colorName(i));
        y_min += y_val.second - y_val.first;
      }
    }*/

    /* multi series unstacked */
    else {
      auto draw_y_multi = draw_y;
      auto draw_height_multi = draw_height / num_series_;
      for (int i = 0; i < bar.ys.size(); i++) {
      auto y_min = y_domain->scale(bar.ys[i].first);
      auto y_max = y_domain->scale(bar.ys[i].second);
        auto draw_x = padding_left + y_min * inner_width;
        auto draw_width = (y_max - y_min) * inner_width;
        target->drawRect(
            draw_x,
            draw_y_multi,
            draw_width,
            draw_height_multi * (1.0f - kBarPadding * 0.5f),
            "color0");
        draw_y_multi += (draw_height_multi * (1.0f + kBarPadding * 0.5f));
      }
    }

    draw_y += bar_height + bar_padding;
  }
}

NumericalDomain* BarChart::getValueDomain() const {
  if (y_domain_ != nullptr) {
    return y_domain_;
  }

  if (y_domain_auto_.get() == nullptr) {
    y_domain_auto_.reset(newValueDomain());
  }

  return y_domain_auto_.get();
}

NumericalDomain* BarChart::newValueDomain() const {
  /* calculate our domain*/
  if (stacked_) {
    /*
    int num_bars = 0;
    for (const auto& series : getSeries()) {
      if (series->getData().size() > num_bars) {
        num_bars = series->getData().size();
      }
    }

    double y_domain_max = 0.0f;
    for (int i = 0; i < num_bars; ++i) {
      int sum = 0;
      for (const auto& series : getSeries()) {
        if (i < series->getData().size()) {
          sum += series->getData()[i][1].getFloat();
        }
      }

      if (sum > y_domain_max) {
        y_domain_max = sum;
      }
    }
    y_domain = Domain(0, y_domain_max, false);
    */
  } else {
    double y_domain_min = 0.0f;
    double y_domain_max = 0.0f;

    for (const auto& group : data_) {
      for (const auto& y : group.ys) {
        if (y.first < y_domain_min) {
          y_domain_min = y.first;
        }
        if (y.first > y_domain_max) {
          y_domain_max = y.first;
        }
        if (y.second < y_domain_min) {
          y_domain_min = y.second;
        }
        if (y.second > y_domain_max) {
          y_domain_max = y.second;
        }
      }
    }

    if (y_domain_max > 0) {
      y_domain_max *= 1.1;
    }

    return new NumericalDomain(y_domain_min, y_domain_max, false);
  }
}

AxisDefinition* BarChart::newLabelAxis(AxisDefinition::kPosition position)
    const {
  auto axis = canvas_->addAxis(position);
  axis->addTick(0.0f);

  auto bar_width = (1.0 / data_.size()) * (1.0f - kBarPadding);
  auto bar_padding = (1.0 / data_.size()) * (kBarPadding * 0.5f);
  bar_width -= bar_padding / data_.size() * 2;

  auto draw_x = bar_padding;
  for (int i = 0; i < data_.size(); ++i) {
    draw_x += bar_padding;

    switch (orientation_) {
      case O_VERTICAL:
        axis->addLabel(draw_x + bar_width * 0.5f, data_[i].x);
        break;
      case O_HORIZONTAL:
        axis->addLabel(
            draw_x + bar_width * 0.5f,
            data_[data_.size() - 1 - i].x);
        break;
    }

    draw_x += bar_width + bar_padding;
    if (i < data_.size() - 1) {
      axis->addTick(draw_x);
    }
  }

  axis->addTick(1.0f);
  return axis;
}

}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2009, Thomas Jaeger <ThJaeger@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include "actiondb.h"
#include "main.h"
#include "win.h"
#include <glibmm/i18n.h>

#include <iostream>
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <X11/extensions/XTest.h>

BOOST_CLASS_EXPORT(StrokeSet)

BOOST_CLASS_EXPORT(Action)
BOOST_CLASS_EXPORT(Command)
BOOST_CLASS_EXPORT(ModAction)
BOOST_CLASS_EXPORT(SendKey)
BOOST_CLASS_EXPORT(Scroll)
BOOST_CLASS_EXPORT(Ignore)
BOOST_CLASS_EXPORT(Button)
BOOST_CLASS_EXPORT(Misc)

template<class Archive> void Unique::serialize(Archive & ar, const unsigned int version) {}

template<class Archive> void Action::serialize(Archive & ar, const unsigned int version) {}

template<class Archive> void Command::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & cmd;
}

template<class Archive> void ModAction::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & mods;
}

template<class Archive> void SendKey::load(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & key;
	ar & code;
	if (version < 1) {
		bool xtest;
		ar & xtest;
	}
	compute_code();
}

template<class Archive> void SendKey::save(Archive & ar, const unsigned int version) const {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & key;
	ar & code;
}

template<class Archive> void Scroll::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
}

template<class Archive> void Ignore::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
}

template<class Archive> void Button::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & button;
}

template<class Archive> void Misc::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & type;
}

template<class Archive> void StrokeSet::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<std::set<RStroke> >(*this);
}

template<class Archive> void StrokeInfo::serialize(Archive & ar, const unsigned int version) {
	ar & strokes;
	ar & action;
	if (version == 0) return;
	ar & name;
}

using namespace std;

void SendKey::compute_code() {
	if (key)
		code = XKeysymToKeycode(dpy, key);
}

void Command::run() {
	pid_t pid = fork();
	switch (pid) {
		case 0:
			execlp("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
			exit(1);
		case -1:
			printf(_("Error: can't execute command \"%s\": fork() failed\n"), cmd.c_str());
	}
}

ButtonInfo Button::get_button_info() const {
	ButtonInfo bi;
	bi.button = button;
	bi.state = mods;
	return bi;
}

const Glib::ustring Button::get_label() const {
	return get_button_info().get_button_text();
}

const char *Misc::types[5] = { "None", "Unminimize", "Show/Hide", "Disable (Enable)", NULL };

template<class Archive> void ActionListDiff::serialize(Archive & ar, const unsigned int version) {
	ar & deleted;
	ar & added;
	ar & name;
	ar & children;
	ar & app;
	if (version == 0)
		return;
	ar & order;
}

template<class Archive> void ActionDB::load(Archive & ar, const unsigned int version) {
	if (version >= 2) {
		ar & root;
	}
	if (version == 1) {
		std::map<int, StrokeInfo> strokes;
		ar & strokes;
		for (std::map<int, StrokeInfo>::iterator i = strokes.begin(); i != strokes.end(); ++i)
			root.add(i->second);
	}
	if (version == 0) {
		std::map<std::string, StrokeInfo> strokes;
		ar & strokes;
		for (std::map<std::string, StrokeInfo>::iterator i = strokes.begin(); i != strokes.end(); ++i) {
			i->second.name = i->first;
			root.add(i->second);
		}
	}

	root.fix_tree(version == 2);
	root.add_apps(apps);
	root.name = _("Default");
}

template<class Archive> void ActionDB::save(Archive & ar, const unsigned int version) const {
	ar & root;
}

Source<bool> action_dummy;

void update_actions() {
	action_dummy.set(false);
}

void ActionDBWatcher::init() {
	std::string filename = config_dir+"actions";
	for (const char **v = versions; *v; v++)
		if (is_file(filename + *v)) {
			filename += *v;
			try {
				ifstream ifs(filename.c_str(), ios::binary);
				if (!ifs.fail()) {
					boost::archive::text_iarchive ia(ifs);
					ia >> actions;
					if (verbosity >= 2)
						printf("Loaded actions.\n");
				}
			} catch (exception &e) {
				printf(_("Error: Couldn't read action database: %s.\n"), e.what());
			}
			break;
		}
	watch(action_dummy);
}

void ActionDBWatcher::timeout() {
	std::string filename = config_dir+"actions"+versions[0];
	std::string tmp = filename + ".tmp";
	try {
		ofstream ofs(tmp.c_str());
		boost::archive::text_oarchive oa(ofs);
		oa << (const ActionDB &)actions;
		if (rename(tmp.c_str(), filename.c_str()))
			throw std::runtime_error(_("rename() failed"));
		if (verbosity >= 2)
			printf("Saved actions.\n");
	} catch (exception &e) {
		printf(_("Error: Couldn't save action database: %s.\n"), e.what());
		if (!good_state)
			return;
		good_state = false;
		new ErrorDialog(Glib::ustring::compose(_( "Couldn't save %1.  Your changes will be lost.  "
				"Make sure that \"%2\" is a directory and that you have write access to it.  "
				"You can change the configuration directory "
				"using the -c or --config-dir command line options."), _("actions"), config_dir));
	}
}

RStrokeInfo ActionListDiff::get_info(Unique *id, bool *deleted, bool *stroke, bool *name, bool *action) const {
	if (deleted)
		*deleted = this->deleted.count(id);
	if (stroke)
		*stroke = false;
	if (name)
		*name = false;
	if (action)
		*action = false;
	RStrokeInfo si = parent ? parent->get_info(id) : RStrokeInfo(new StrokeInfo);
	std::map<Unique *, StrokeInfo>::const_iterator i = added.find(id);
	for (i = added.begin(); i != added.end(); i++) {
		if (i->first == id)
			break;
	}
	if (i == added.end()) {
		return si;
	}
	if (i->second.name != "") {
		si->name = i->second.name;
		if (name)
			*name = parent;
	}
	if (i->second.strokes.size()) {
		si->strokes = i->second.strokes;
		if (stroke)
			*stroke = parent;
	}
	if (i->second.action) {
		si->action = i->second.action;
		if (action)
			*action = parent;
	}
	return si;
}

boost::shared_ptr<std::map<Unique *, StrokeSet> > ActionListDiff::get_strokes() const {
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = parent ? parent->get_strokes() :
		boost::shared_ptr<std::map<Unique *, StrokeSet> >(new std::map<Unique *, StrokeSet>);
	for (std::set<Unique *>::const_iterator i = deleted.begin(); i != deleted.end(); i++)
		strokes->erase(*i);
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		if (i->second.strokes.size())
			(*strokes)[i->first] = i->second.strokes;
	return strokes;
}

boost::shared_ptr<std::set<Unique *> > ActionListDiff::get_ids(bool include_deleted) const {
	boost::shared_ptr<std::set<Unique *> > ids = parent ? parent->get_ids(false) :
		boost::shared_ptr<std::set<Unique *> >(new std::set<Unique *>);
	if (!include_deleted)
		for (std::set<Unique *>::const_iterator i = deleted.begin(); i != deleted.end(); i++)
			ids->erase(*i);
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		ids->insert(i->first);
	return ids;
}

void ActionListDiff::all_strokes(std::list<RStroke> &strokes) const {
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		for (std::set<RStroke>::const_iterator j = i->second.strokes.begin(); j != i->second.strokes.end(); j++)
			strokes.push_back(*j);
	for (std::list<ActionListDiff>::const_iterator i = children.begin(); i != children.end(); i++)
		i->all_strokes(strokes);
}

RAction ActionListDiff::handle(RStroke s, Ranking &r) const {
	if (!s)
		return RAction();
	r.stroke = s;
	r.score = -1;
	r.id = NULL;
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = get_strokes();
	for (std::map<Unique *, StrokeSet>::const_iterator i = strokes->begin(); i!=strokes->end(); i++) {
		for (StrokeSet::iterator j = i->second.begin(); j!=i->second.end(); j++) {
			double score;
			bool match = Stroke::compare(s, *j, score);
			if (score < 0.25)
				continue;
			RStrokeInfo si = get_info(i->first);
			r.r.insert(pair<double, pair<std::string, RStroke> >
					(score, pair<std::string, RStroke>(si->name, *j)));
			if (score >= r.score) {
				r.score = score;
				if (match) {
					r.id = i->first;
					r.name = si->name;
					r.action = si->action;
					r.best_stroke = *j;
				}
			}
		}
	}
	if (!r.action && s->trivial()) {
		r.action = RAction(new Click);
		r.name = _("click (default)");
	}
	if (r.action) {
		if (verbosity >= 1)
			printf("Executing Action %s\n", r.name.c_str());
	} else {
		if (verbosity >= 1)
			printf("Couldn't find matching stroke.\n");
	}
	return r.action;
}

void ActionListDiff::handle_advanced(RStroke s, std::map<guint, RAction> &as,
		std::map<guint, Ranking *> &rs, int b1, int b2) const {
	if (!s)
		return;
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = get_strokes();
	for (std::map<Unique *, StrokeSet>::const_iterator i = strokes->begin(); i!=strokes->end(); i++) {
		for (StrokeSet::iterator j = i->second.begin(); j!=i->second.end(); j++) {
			int b = (*j)->button;
			if (!s->timeout && !b)
				continue;
			s->button = b;
			double score;
			bool match = Stroke::compare(s, *j, score);
			if (score < 0.25)
				continue;
			Ranking *r;
			if (b == b1)
				b = b2;
			if (rs.count(b)) {
				r = rs[b];
			} else {
				r = new Ranking;
				rs[b] = r;
				r->stroke = RStroke(new Stroke(*s));
				r->score = -1;
				r->id = NULL;
			}
			RStrokeInfo si = get_info(i->first);
			r->r.insert(pair<double, pair<std::string, RStroke> >
					(score, pair<std::string, RStroke>(si->name, *j)));
			if (score >= r->score) {
				r->score = score;
				if (match) {
					r->id = i->first;
					r->name = si->name;
					r->action = si->action;
					r->best_stroke = *j;
					as[b] = si->action;
				}
			}
		}
	}
}

ActionListDiff::~ActionListDiff() {
	if (app)
		actions.apps.erase(name);
}

ActionDB actions;
<commit_msg>We don't need to document every click<commit_after>/*
 * Copyright (c) 2008-2009, Thomas Jaeger <ThJaeger@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include "actiondb.h"
#include "main.h"
#include "win.h"
#include <glibmm/i18n.h>

#include <iostream>
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <X11/extensions/XTest.h>

BOOST_CLASS_EXPORT(StrokeSet)

BOOST_CLASS_EXPORT(Action)
BOOST_CLASS_EXPORT(Command)
BOOST_CLASS_EXPORT(ModAction)
BOOST_CLASS_EXPORT(SendKey)
BOOST_CLASS_EXPORT(Scroll)
BOOST_CLASS_EXPORT(Ignore)
BOOST_CLASS_EXPORT(Button)
BOOST_CLASS_EXPORT(Misc)

template<class Archive> void Unique::serialize(Archive & ar, const unsigned int version) {}

template<class Archive> void Action::serialize(Archive & ar, const unsigned int version) {}

template<class Archive> void Command::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & cmd;
}

template<class Archive> void ModAction::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & mods;
}

template<class Archive> void SendKey::load(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & key;
	ar & code;
	if (version < 1) {
		bool xtest;
		ar & xtest;
	}
	compute_code();
}

template<class Archive> void SendKey::save(Archive & ar, const unsigned int version) const {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & key;
	ar & code;
}

template<class Archive> void Scroll::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
}

template<class Archive> void Ignore::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
}

template<class Archive> void Button::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<ModAction>(*this);
	ar & button;
}

template<class Archive> void Misc::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<Action>(*this);
	ar & type;
}

template<class Archive> void StrokeSet::serialize(Archive & ar, const unsigned int version) {
	ar & boost::serialization::base_object<std::set<RStroke> >(*this);
}

template<class Archive> void StrokeInfo::serialize(Archive & ar, const unsigned int version) {
	ar & strokes;
	ar & action;
	if (version == 0) return;
	ar & name;
}

using namespace std;

void SendKey::compute_code() {
	if (key)
		code = XKeysymToKeycode(dpy, key);
}

void Command::run() {
	pid_t pid = fork();
	switch (pid) {
		case 0:
			execlp("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
			exit(1);
		case -1:
			printf(_("Error: can't execute command \"%s\": fork() failed\n"), cmd.c_str());
	}
}

ButtonInfo Button::get_button_info() const {
	ButtonInfo bi;
	bi.button = button;
	bi.state = mods;
	return bi;
}

const Glib::ustring Button::get_label() const {
	return get_button_info().get_button_text();
}

const char *Misc::types[5] = { "None", "Unminimize", "Show/Hide", "Disable (Enable)", NULL };

template<class Archive> void ActionListDiff::serialize(Archive & ar, const unsigned int version) {
	ar & deleted;
	ar & added;
	ar & name;
	ar & children;
	ar & app;
	if (version == 0)
		return;
	ar & order;
}

template<class Archive> void ActionDB::load(Archive & ar, const unsigned int version) {
	if (version >= 2) {
		ar & root;
	}
	if (version == 1) {
		std::map<int, StrokeInfo> strokes;
		ar & strokes;
		for (std::map<int, StrokeInfo>::iterator i = strokes.begin(); i != strokes.end(); ++i)
			root.add(i->second);
	}
	if (version == 0) {
		std::map<std::string, StrokeInfo> strokes;
		ar & strokes;
		for (std::map<std::string, StrokeInfo>::iterator i = strokes.begin(); i != strokes.end(); ++i) {
			i->second.name = i->first;
			root.add(i->second);
		}
	}

	root.fix_tree(version == 2);
	root.add_apps(apps);
	root.name = _("Default");
}

template<class Archive> void ActionDB::save(Archive & ar, const unsigned int version) const {
	ar & root;
}

Source<bool> action_dummy;

void update_actions() {
	action_dummy.set(false);
}

void ActionDBWatcher::init() {
	std::string filename = config_dir+"actions";
	for (const char **v = versions; *v; v++)
		if (is_file(filename + *v)) {
			filename += *v;
			try {
				ifstream ifs(filename.c_str(), ios::binary);
				if (!ifs.fail()) {
					boost::archive::text_iarchive ia(ifs);
					ia >> actions;
					if (verbosity >= 2)
						printf("Loaded actions.\n");
				}
			} catch (exception &e) {
				printf(_("Error: Couldn't read action database: %s.\n"), e.what());
			}
			break;
		}
	watch(action_dummy);
}

void ActionDBWatcher::timeout() {
	std::string filename = config_dir+"actions"+versions[0];
	std::string tmp = filename + ".tmp";
	try {
		ofstream ofs(tmp.c_str());
		boost::archive::text_oarchive oa(ofs);
		oa << (const ActionDB &)actions;
		if (rename(tmp.c_str(), filename.c_str()))
			throw std::runtime_error(_("rename() failed"));
		if (verbosity >= 2)
			printf("Saved actions.\n");
	} catch (exception &e) {
		printf(_("Error: Couldn't save action database: %s.\n"), e.what());
		if (!good_state)
			return;
		good_state = false;
		new ErrorDialog(Glib::ustring::compose(_( "Couldn't save %1.  Your changes will be lost.  "
				"Make sure that \"%2\" is a directory and that you have write access to it.  "
				"You can change the configuration directory "
				"using the -c or --config-dir command line options."), _("actions"), config_dir));
	}
}

RStrokeInfo ActionListDiff::get_info(Unique *id, bool *deleted, bool *stroke, bool *name, bool *action) const {
	if (deleted)
		*deleted = this->deleted.count(id);
	if (stroke)
		*stroke = false;
	if (name)
		*name = false;
	if (action)
		*action = false;
	RStrokeInfo si = parent ? parent->get_info(id) : RStrokeInfo(new StrokeInfo);
	std::map<Unique *, StrokeInfo>::const_iterator i = added.find(id);
	for (i = added.begin(); i != added.end(); i++) {
		if (i->first == id)
			break;
	}
	if (i == added.end()) {
		return si;
	}
	if (i->second.name != "") {
		si->name = i->second.name;
		if (name)
			*name = parent;
	}
	if (i->second.strokes.size()) {
		si->strokes = i->second.strokes;
		if (stroke)
			*stroke = parent;
	}
	if (i->second.action) {
		si->action = i->second.action;
		if (action)
			*action = parent;
	}
	return si;
}

boost::shared_ptr<std::map<Unique *, StrokeSet> > ActionListDiff::get_strokes() const {
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = parent ? parent->get_strokes() :
		boost::shared_ptr<std::map<Unique *, StrokeSet> >(new std::map<Unique *, StrokeSet>);
	for (std::set<Unique *>::const_iterator i = deleted.begin(); i != deleted.end(); i++)
		strokes->erase(*i);
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		if (i->second.strokes.size())
			(*strokes)[i->first] = i->second.strokes;
	return strokes;
}

boost::shared_ptr<std::set<Unique *> > ActionListDiff::get_ids(bool include_deleted) const {
	boost::shared_ptr<std::set<Unique *> > ids = parent ? parent->get_ids(false) :
		boost::shared_ptr<std::set<Unique *> >(new std::set<Unique *>);
	if (!include_deleted)
		for (std::set<Unique *>::const_iterator i = deleted.begin(); i != deleted.end(); i++)
			ids->erase(*i);
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		ids->insert(i->first);
	return ids;
}

void ActionListDiff::all_strokes(std::list<RStroke> &strokes) const {
	for (std::map<Unique *, StrokeInfo>::const_iterator i = added.begin(); i != added.end(); i++)
		for (std::set<RStroke>::const_iterator j = i->second.strokes.begin(); j != i->second.strokes.end(); j++)
			strokes.push_back(*j);
	for (std::list<ActionListDiff>::const_iterator i = children.begin(); i != children.end(); i++)
		i->all_strokes(strokes);
}

RAction ActionListDiff::handle(RStroke s, Ranking &r) const {
	if (!s)
		return RAction();
	r.stroke = s;
	r.score = -1;
	r.id = NULL;
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = get_strokes();
	for (std::map<Unique *, StrokeSet>::const_iterator i = strokes->begin(); i!=strokes->end(); i++) {
		for (StrokeSet::iterator j = i->second.begin(); j!=i->second.end(); j++) {
			double score;
			bool match = Stroke::compare(s, *j, score);
			if (score < 0.25)
				continue;
			RStrokeInfo si = get_info(i->first);
			r.r.insert(pair<double, pair<std::string, RStroke> >
					(score, pair<std::string, RStroke>(si->name, *j)));
			if (score >= r.score) {
				r.score = score;
				if (match) {
					r.id = i->first;
					r.name = si->name;
					r.action = si->action;
					r.best_stroke = *j;
				}
			}
		}
	}
	if (!r.action && s->trivial())
		return RAction(new Click);
	if (r.action) {
		if (verbosity >= 1)
			printf("Executing Action %s\n", r.name.c_str());
	} else {
		if (verbosity >= 1)
			printf("Couldn't find matching stroke.\n");
	}
	return r.action;
}

void ActionListDiff::handle_advanced(RStroke s, std::map<guint, RAction> &as,
		std::map<guint, Ranking *> &rs, int b1, int b2) const {
	if (!s)
		return;
	boost::shared_ptr<std::map<Unique *, StrokeSet> > strokes = get_strokes();
	for (std::map<Unique *, StrokeSet>::const_iterator i = strokes->begin(); i!=strokes->end(); i++) {
		for (StrokeSet::iterator j = i->second.begin(); j!=i->second.end(); j++) {
			int b = (*j)->button;
			if (!s->timeout && !b)
				continue;
			s->button = b;
			double score;
			bool match = Stroke::compare(s, *j, score);
			if (score < 0.25)
				continue;
			Ranking *r;
			if (b == b1)
				b = b2;
			if (rs.count(b)) {
				r = rs[b];
			} else {
				r = new Ranking;
				rs[b] = r;
				r->stroke = RStroke(new Stroke(*s));
				r->score = -1;
				r->id = NULL;
			}
			RStrokeInfo si = get_info(i->first);
			r->r.insert(pair<double, pair<std::string, RStroke> >
					(score, pair<std::string, RStroke>(si->name, *j)));
			if (score >= r->score) {
				r->score = score;
				if (match) {
					r->id = i->first;
					r->name = si->name;
					r->action = si->action;
					r->best_stroke = *j;
					as[b] = si->action;
				}
			}
		}
	}
}

ActionListDiff::~ActionListDiff() {
	if (app)
		actions.apps.erase(name);
}

ActionDB actions;
<|endoftext|>


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

#include "activity.h"

#include "glog/logging.h"

namespace distbench {

std::unique_ptr<Activity> AllocateActivity(ParsedActivityConfig* config) {
  std::unique_ptr<Activity> activity;
  auto activity_func = config->activity_func;

  if (activity_func == "WasteCpu") {
    activity = std::make_unique<WasteCpu>();
  } else if (activity_func == "PolluteDataCache") {
    activity = std::make_unique<PolluteDataCache>();
  }

  activity->Initialize(config);
  return activity;
}

// Activity: WasteCpu

void WasteCpu::DoActivity() {
  iteration_count_++;
  int sum = 0;
  std::srand(time(0));
  std::generate(rand_array.begin(), rand_array.end(), std::rand);
  std::sort(rand_array.begin(), rand_array.end());
  for (auto num : rand_array) sum += num;
  optimization_preventing_num_ = sum;
}

ActivityLog WasteCpu::GetActivityLog() {
  ActivityLog alog;
  if (iteration_count_) {
    auto* am = alog.add_activity_metrics();
    am->set_name("iteration_count");
    am->set_value_int(iteration_count_);
  }
  return alog;
}

void WasteCpu::Initialize(ParsedActivityConfig* config) {
  rand_array.resize(config->waste_cpu_config.array_size);
  iteration_count_ = 0;
}

absl::Status WasteCpu::ValidateConfig(ActivityConfig& ac) {
  auto array_size =
      GetNamedSettingInt64(ac.activity_settings(), "array_size", 1000);
  if (array_size < 1) {
    return absl::InvalidArgumentError(absl::StrCat(
        "Array size (", array_size, ") must be a positive integer."));
  }
  return absl::OkStatus();
}

// Activity: PolluteDataCache

absl::Status PolluteDataCache::ValidateConfig(ActivityConfig& ac) {
  auto array_size =
      GetNamedSettingInt64(ac.activity_settings(), "array_size", 1000);
  if (array_size < 1) {
    return absl::InvalidArgumentError(absl::StrCat(
        "Array size (", array_size, ") must be a positive integer."));
  }

  auto array_reads_per_iteration = GetNamedSettingInt64(
      ac.activity_settings(), "array_reads_per_iteration", 1000);
  if (array_reads_per_iteration < 1) {
    return absl::InvalidArgumentError(
        absl::StrCat("Array reads per iteration (", array_reads_per_iteration,
                     ") must be a positive integer."));
  }
  return absl::OkStatus();
}

void PolluteDataCache::Initialize(ParsedActivityConfig* config) {
  std::srand(time(0));
  auto array_size = config->pollute_data_cache_config.array_size;

  data_array_.resize(array_size);
  for (int i = 0; i < array_size; i++) {
    data_array_[i] = i;
  }

  random_index_ = std::uniform_int_distribution<>(0, array_size - 1);
  array_reads_per_iteration_ =
      config->pollute_data_cache_config.array_reads_per_iteration;
  iteration_count_ = 0;

  std::random_device rd;
  mersenne_twister_prng_ = std::mt19937(rd());
}

void PolluteDataCache::DoActivity() {
  iteration_count_++;
  int64_t sum = 0;
  for (int i = 0; i < array_reads_per_iteration_; i++) {
    int index = random_index_(mersenne_twister_prng_);

    // This is read and write operation.
    sum += data_array_[index]++;
  }
  optimization_preventing_num_ = sum;
}

ActivityLog PolluteDataCache::GetActivityLog() {
  ActivityLog alog;
  if (iteration_count_) {
    auto* am = alog.add_activity_metrics();
    am->set_name("iteration_count");
    am->set_value_int(iteration_count_);
  }
  return alog;
}

}  // namespace distbench
<commit_msg>activity.cc: Avoid signed integer overflow undefined behavior warning.<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "activity.h"

#include "glog/logging.h"

namespace distbench {

std::unique_ptr<Activity> AllocateActivity(ParsedActivityConfig* config) {
  std::unique_ptr<Activity> activity;
  auto activity_func = config->activity_func;

  if (activity_func == "WasteCpu") {
    activity = std::make_unique<WasteCpu>();
  } else if (activity_func == "PolluteDataCache") {
    activity = std::make_unique<PolluteDataCache>();
  }

  activity->Initialize(config);
  return activity;
}

// Activity: WasteCpu

void WasteCpu::DoActivity() {
  iteration_count_++;
  unsigned int sum = 0;
  std::srand(time(0));
  std::generate(rand_array.begin(), rand_array.end(), std::rand);
  std::sort(rand_array.begin(), rand_array.end());
  for (auto num : rand_array) sum += num;
  optimization_preventing_num_ = sum;
}

ActivityLog WasteCpu::GetActivityLog() {
  ActivityLog alog;
  if (iteration_count_) {
    auto* am = alog.add_activity_metrics();
    am->set_name("iteration_count");
    am->set_value_int(iteration_count_);
  }
  return alog;
}

void WasteCpu::Initialize(ParsedActivityConfig* config) {
  rand_array.resize(config->waste_cpu_config.array_size);
  iteration_count_ = 0;
}

absl::Status WasteCpu::ValidateConfig(ActivityConfig& ac) {
  auto array_size =
      GetNamedSettingInt64(ac.activity_settings(), "array_size", 1000);
  if (array_size < 1) {
    return absl::InvalidArgumentError(absl::StrCat(
        "Array size (", array_size, ") must be a positive integer."));
  }
  return absl::OkStatus();
}

// Activity: PolluteDataCache

absl::Status PolluteDataCache::ValidateConfig(ActivityConfig& ac) {
  auto array_size =
      GetNamedSettingInt64(ac.activity_settings(), "array_size", 1000);
  if (array_size < 1) {
    return absl::InvalidArgumentError(absl::StrCat(
        "Array size (", array_size, ") must be a positive integer."));
  }

  auto array_reads_per_iteration = GetNamedSettingInt64(
      ac.activity_settings(), "array_reads_per_iteration", 1000);
  if (array_reads_per_iteration < 1) {
    return absl::InvalidArgumentError(
        absl::StrCat("Array reads per iteration (", array_reads_per_iteration,
                     ") must be a positive integer."));
  }
  return absl::OkStatus();
}

void PolluteDataCache::Initialize(ParsedActivityConfig* config) {
  std::srand(time(0));
  auto array_size = config->pollute_data_cache_config.array_size;

  data_array_.resize(array_size);
  for (int i = 0; i < array_size; i++) {
    data_array_[i] = i;
  }

  random_index_ = std::uniform_int_distribution<>(0, array_size - 1);
  array_reads_per_iteration_ =
      config->pollute_data_cache_config.array_reads_per_iteration;
  iteration_count_ = 0;

  std::random_device rd;
  mersenne_twister_prng_ = std::mt19937(rd());
}

void PolluteDataCache::DoActivity() {
  iteration_count_++;
  int64_t sum = 0;
  for (int i = 0; i < array_reads_per_iteration_; i++) {
    int index = random_index_(mersenne_twister_prng_);

    // This is read and write operation.
    sum += data_array_[index]++;
  }
  optimization_preventing_num_ = sum;
}

ActivityLog PolluteDataCache::GetActivityLog() {
  ActivityLog alog;
  if (iteration_count_) {
    auto* am = alog.add_activity_metrics();
    am->set_name("iteration_count");
    am->set_value_int(iteration_count_);
  }
  return alog;
}

}  // namespace distbench
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include "MethodDefinition.h"
#include "../execution/Program.h"

void MethodDefinition::execute() {
    Program::create_frame(frame_size);

    for (unsigned int i = 0; i < arguments; i++) {
        Program::frame()[i] = Program::pop();
    }

    for (int counter = 0; counter < symbols.size();) {
        auto symbol = symbols[counter];

        std::cerr << "[" << counter << "] Executing symbol " << describe(symbol.opcode) << ": " << symbol.target << ", "
                  << symbol.secondary << " -> [";
        std::for_each(Program::frame().begin(), Program::frame().end(),
                      [](const PThingInstance &thing) { std::cerr << (thing ? thing->text() : "?") << ","; });
        std::cerr << "] -> ";
        std::for_each(Program::static_data.begin(), Program::static_data.end(),
                      [](const PThingInstance &thing) { std::cerr << (thing ? thing->text() : "?") << ","; });
        std::cerr << "]" << std::endl;

        switch (symbol.opcode) {

            case Opcode::NOP:
                break;

            case Opcode::PUSH: {
                Program::push(Program::frame()[symbol.target]);
                break;
            };

            case Opcode::PUSH_NULL: {
                Program::push(NULL);
                break;
            }

            case Opcode::POP: {
                Program::pop();
                break;
            }

            case Opcode::SET_STATIC: {
                Program::frame()[symbol.target] = Program::data(symbol.secondary);
                break;
            }

            case Opcode::SET: {
                Program::frame()[symbol.target] = Program::pop();
                break;
            }

            case Opcode::PUSH_STATIC: {
                Program::push(Program::data(symbol.target));
                break;
            }

            case Opcode::CALL: {
                auto instance = Program::top();
                instance->call_method(symbol.target);

                break;
            }

            case Opcode::CALL_METHOD: {
                auto instance = Program::instance();
                instance->call_method(symbol.target);
                break;
            }

            case Opcode::PRINT:
                std::cout << Program::pop()->text() << std::endl;
                break;

            case Opcode::CALL_INTERNAL: {
                Program::internals[symbol.target]->call_internal(symbol.secondary);
                break;
            }

            case Opcode::RETURN: {
                Program::pop_frame();
                break;
            }

            case Opcode::JUMP: {
                counter = symbol.target;
                continue;
            }

            case Opcode::CONDITIONAL_JUMP: {
                auto value = Program::pop();
                if (!value) {
                    counter = symbol.target;
                    continue;
                }
                break;
            }

            default:
                throw RuntimeError(
                        "Cannot handle symbol " + describe(symbol.opcode) + " (" + std::to_string((int) symbol.opcode) +
                        ")");
        }

        counter++;
    };

    Program::pop_frame();
}

<commit_msg>Fix return opcode handling<commit_after>#include <iostream>
#include <algorithm>
#include "MethodDefinition.h"
#include "../execution/Program.h"

void MethodDefinition::execute() {
    Program::create_frame(frame_size);

    for (unsigned int i = 0; i < arguments; i++) {
        Program::frame()[i] = Program::pop();
    }

    auto counter_end = symbols.size();

    for (auto counter = 0; counter < counter_end;) {
        auto symbol = symbols[counter];

        std::cerr << "[" << counter << "] Executing symbol " << describe(symbol.opcode) << ": " << symbol.target << ", "
                  << symbol.secondary << " -> [";
        std::for_each(Program::frame().begin(), Program::frame().end(),
                      [](const PThingInstance &thing) { std::cerr << (thing ? thing->text() : "?") << ","; });
        std::cerr << "] -> [";
        std::for_each(Program::static_data.begin(), Program::static_data.end(),
                      [](const PThingInstance &thing) { std::cerr << (thing ? thing->text() : "?") << ","; });
        std::cerr << "]" << std::endl;

        switch (symbol.opcode) {

            case Opcode::NOP:
                break;

            case Opcode::PUSH: {
                Program::push(Program::frame()[symbol.target]);
                break;
            };

            case Opcode::PUSH_NULL: {
                Program::push(NULL);
                break;
            }

            case Opcode::POP: {
                Program::pop();
                break;
            }

            case Opcode::SET_STATIC: {
                Program::frame()[symbol.target] = Program::data(symbol.secondary);
                break;
            }

            case Opcode::SET: {
                Program::frame()[symbol.target] = Program::pop();
                break;
            }

            case Opcode::PUSH_STATIC: {
                Program::push(Program::data(symbol.target));
                break;
            }

            case Opcode::CALL: {
                auto instance = Program::top();
                instance->call_method(symbol.target);

                break;
            }

            case Opcode::CALL_METHOD: {
                auto instance = Program::instance();
                instance->call_method(symbol.target);
                break;
            }

            case Opcode::PRINT:
                std::cout << Program::pop()->text() << std::endl;
                break;

            case Opcode::CALL_INTERNAL: {
                Program::internals[symbol.target]->call_internal(symbol.secondary);
                break;
            }

            case Opcode::RETURN: {
                counter = counter_end;
                continue;
            }

            case Opcode::JUMP: {
                counter = symbol.target;
                continue;
            }

            case Opcode::CONDITIONAL_JUMP: {
                auto value = Program::pop();
                if (!value) {
                    counter = symbol.target;
                    continue;
                }
                break;
            }

            default:
                throw RuntimeError(
                        "Cannot handle symbol " + describe(symbol.opcode) + " (" + std::to_string((int) symbol.opcode) +
                        ")");
        }

        counter++;
    };

    Program::pop_frame();
}

<|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2014

    This file is part of Lasercake.

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

    Lasercake 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_TAIL_DROP_MAP_HPP__
#define LASERCAKE_TAIL_DROP_MAP_HPP__

/*

This is a bizarrely specific data structure that might be useful for the time steward.

It implements only two operations:
void insert (key, value), which inserts an element into the map, and
tail_drop (key), which removes and returns all elements with keys after key, not necessarily in order.

Inserting at the end is O(1) worst case.
Inserting elsewhere is O(1), but incurs a debt of up to O(log n) which will be paid off later by tail_drop.
tail_drop is merely O(number of things returned), plus paying off the debt.

Since the results of tail_drop don't actually need to be sorted,
we delay all or part of the O(log n) cost of sorting for as long as we can,
in the hopes of never having to pay it at all.

There is also discard_head (key), which can be used to save memory by assuring the tail_drop_map that you won't query before key, so it can discard some data that it knows will never be used. However, it does not guarantee that all data before key will be discarded.

*/

template <typename key_type, typename mapped_type>
class tail_drop_map {
private:
  //the "bucket" type is used only for collecting unsorted elements
  //1 at a time, then eventually iterating them and dumping them all out.
  typedef std:: vector bucket;
  typedef std:: pair <key_type, mapped_type> value_type;

  struct sorted_element {
    sorted_element (value_type const & value): value (value) {}
    value_type value;
    bucket unsorted_elements_before_or_equal_this;
  };
  std:: vector <sorted_element> sorted_elements;
  bucket unsorted_elements;

public:
  void insert (value_type const & value) {
    if (value.first >= sorted_elements.back ().value.first) {
      sorted_elements.emplace_back (value);
    }
    else {
      unsorted_elements.push_back (value);
    }
  }

  template <class output_function>
  void tail_drop (key_type const & key, output_function output = output_function ()) {
    if (sorted_elements.empty ()) {
      assert (unsorted_elements.empty ());
      return;
    }
    while (sorted_elements.back ().value.first >key) {
      bucket & spilling = sorted_elements.back ().unsorted_elements_before_or_equal_this;
      std:: move (spilling.begin (), spilling.end (), std:: back_inserter (unsorted_elements));
      output (sorted_elements.back ().value);
      sorted_elements.pop_back ();
    }

    remaining_sorted= sorted_elements.size ();
    for (value_type value: unsorted_elements) {
      if (value.first >key) {
        output (value);
      }
      else if (sorted_elements.empty () ||
          value.first >= sorted_elements [remaining_sorted-1].value.first) {
        sorted_elements.emplace_back (value);
      }
      else {
        //do part of a binary search, but don't do more than you have to.
        //If there's never a tail_drop that goes back that far,
        //you never have to do the rest of the search, AND
        //if there IS a tail_drop that goes far enough back to
        //actually OUTPUT this element, we never have to do the rest
        //of the search in that scenario either.
        size_t dump_location = remaining_sorted>> 1;
        while (sorted_elements [dump_location].value.first < value.first) {
          dump_location = (dump_location + remaining_sorted) >> 1;
        }
        sorted_elements [dump_location].unsorted_elements_before_or_equal_this
          .push_back (value);
      }
    }
    unsorted_elements.clear ();
    if (sorted_elements.size () >remaining_sorted + 1) {
      std:: sort (sorted_elements [remaining_sorted], sorted_elements.end (),
        [] (e1, e2) {return e1.value.first < e2.value.first});
    }
  }

  void discard_head (key_type const & key) {
    //this could probably be improved
    if (sorted_elements.empty ()) { return;}
    auto middle = sorted_elements.begin () + (sorted_elements.size () >> 1);
    if (middle -> value.first <key) {
      sorted_elements.erase (sorted_elements.begin (), middle);
    }
  }
};

#endif
<commit_msg>Made some improvements to tail_drop_map<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2014

    This file is part of Lasercake.

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

    Lasercake 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_TAIL_DROP_MAP_HPP__
#define LASERCAKE_TAIL_DROP_MAP_HPP__

/*

This is a bizarrely specific data structure that might be useful for the time steward.

It implements only two operations:
void insert (key, value), which inserts an element into the map, and
tail_drop (key), which removes and returns all elements with keys after key, not necessarily in order.

Inserting at the end is O(1) amortized.
Inserting elsewhere is O(1), but incurs a debt of O(log n) which will be paid off later by tail_drop.
tail_drop is merely O(number of things returned), plus paying off the debt.

Since the results of tail_drop don't actually need to be sorted,
we delay all or part of the O(log n) cost of sorting for as long as we can,
in the hopes of never having to pay it at all.

There is also discard_head (key), which can be used to save memory
by assuring the tail_drop_map that you won't query before key,
so it can discard some data that it knows will never be used.
However, it does not guarantee that all data before key will be discarded.

*/

template <typename key_type, typename mapped_type>
class tail_drop_map {
private:
  typedef std:: pair <key_type, mapped_type> value_type;
  //the "bucket" type is used only for collecting unsorted elements
  //1 at a time, then eventually iterating them and dumping them all out.
  typedef std:: vector <value_type> bucket;

  struct sorted_element {
    sorted_element (value_type const & value): value (value) {}
    value_type value;
    bucket unsorted_elements_before_or_equal_this;
  };
  std:: vector <sorted_element> sorted_elements;
  bucket unsorted_elements;

public:
  void insert (value_type const & value) {
    if (value.first >= sorted_elements.back ().value.first) {
      sorted_elements.emplace_back (value);
    }
    else {
      unsorted_elements.push_back (value);
    }
  }

  template <class output_function>
  void tail_drop (key_type const & key, output_function output = output_function ()) {
    if (sorted_elements.empty ()) {
      assert (unsorted_elements.empty ());
      return;
    }
    while (sorted_elements.back ().value.first >key) {
      bucket & spilling = sorted_elements.back ().unsorted_elements_before_or_equal_this;
      std:: move (spilling.begin (), spilling.end (), std:: back_inserter (unsorted_elements));
      output (sorted_elements.back ().value);
      sorted_elements.pop_back ();
    }

    remaining_sorted= sorted_elements.size ();
    for (value_type value: unsorted_elements) {
      if (value.first >key) {
        output (value);
      }
      else if (sorted_elements.empty () ||
          value.first >= sorted_elements [remaining_sorted-1].value.first) {
        sorted_elements.emplace_back (value);
      }
      else {
        //do part of a binary search, but don't do more than you have to.
        //If there's never a tail_drop that goes back that far,
        //you never have to do the rest of the search, AND
        //if there IS a tail_drop that goes far enough back to
        //actually OUTPUT this element, we never have to do the rest
        //of the search in that scenario either.
        size_t dump_location = remaining_sorted>> 1;
        while (sorted_elements [dump_location].value.first < value.first) {
          dump_location = (dump_location + remaining_sorted) >> 1;
        }
        sorted_elements [dump_location].unsorted_elements_before_or_equal_this
          .push_back (value);
      }
    }
    unsorted_elements.clear ();
    if (sorted_elements.size () >remaining_sorted + 1) {
      std:: sort (sorted_elements [remaining_sorted], sorted_elements.end (),
        [] (e1, e2) {return e1.value.first < e2.value.first});
    }
  }

  void discard_head (key_type const & key) {
    //this could probably be improved
    if (sorted_elements.empty ()) { return;}
    auto middle = sorted_elements.begin () + (sorted_elements.size () >> 1);
    if (middle -> value.first <key) {
      sorted_elements.erase (sorted_elements.begin (), middle);
    }
  }
};

#endif
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "../src/Repl.hpp"
#include "../src/Exp.hpp"

#include <sstream>
#include <string>

using namespace sexp_cpp;

namespace
{
  TEST(EvalSpec, EmptyListExp)
  {
    std::stringstream code("()");

    pExp exp = eval(read(code));
    EXPECT_EQ(exp->WhoAmI(), "EmptyListExp");
    EXPECT_EQ("", print(exp));
  }

  TEST(EvalSpec, PairExp)
  {
    std::stringstream code("( 1 2 )");

    pExp exp = read(code);
    EXPECT_EQ(exp->WhoAmI(), "PairExp");

    exp = eval(exp);

    EXPECT_EQ(exp->WhoAmI(), "PairExp");
    EXPECT_EQ("(1 2)", print(exp));
  }

  TEST(EvalSpec, NestedPairExp)
  {
    std::stringstream code("( 1 2 3 4 5 )");
    pExp exp = eval(read(code));

    EXPECT_EQ(exp->WhoAmI(), "PairExp");
    EXPECT_EQ("(1 2 3 4 5)", print(exp));
  }

  //TEST(EvalSpec, Quote)
  //{
    //std::stringstream code("( quote a )");
    //pExp exp = eval(read(code));

    //EXPECT_EQ(exp->WhoAmI(), "PairExp");
    //EXPECT_EQ("a", print(exp));
  //}

}

<commit_msg>added integers spec test<commit_after>#include <gtest/gtest.h>

#include "../src/Repl.hpp"
#include "../src/Exp.hpp"

#include <sstream>
#include <string>

using namespace sexp_cpp;

namespace
{
  TEST(EvalSpec, PositiveIntegerExp)
  {
    std::stringstream code("123");

    pExp exp = eval(read(code));
    EXPECT_EQ(exp->WhoAmI(), "ValueExp");
    EXPECT_EQ("123", print(exp));
  }

  TEST(EvalSpec, NegativeIntegerExp)
  {
    std::stringstream code("-456");

    pExp exp = eval(read(code));
    EXPECT_EQ(exp->WhoAmI(), "ValueExp");
    EXPECT_EQ("-456", print(exp));
  }

  TEST(EvalSpec, EmptyListExp)
  {
    std::stringstream code("()");

    pExp exp = eval(read(code));
    EXPECT_EQ(exp->WhoAmI(), "EmptyListExp");
    EXPECT_EQ("", print(exp));
  }

  TEST(EvalSpec, PairExp)
  {
    std::stringstream code("( 1 2 )");

    pExp exp = read(code);
    EXPECT_EQ(exp->WhoAmI(), "PairExp");

    exp = eval(exp);

    EXPECT_EQ(exp->WhoAmI(), "PairExp");
    EXPECT_EQ("(1 2)", print(exp));
  }

  TEST(EvalSpec, NestedPairExp)
  {
    std::stringstream code("( 1 2 3 4 5 )");
    pExp exp = eval(read(code));

    EXPECT_EQ(exp->WhoAmI(), "PairExp");
    EXPECT_EQ("(1 2 3 4 5)", print(exp));
  }

  //TEST(EvalSpec, Quote)
  //{
    //std::stringstream code("( quote a )");
    //pExp exp = eval(read(code));

    //EXPECT_EQ(exp->WhoAmI(), "PairExp");
    //EXPECT_EQ("a", print(exp));
  //}

}

<|endoftext|>


<commit_before>#include <stdio.h>
#include "log4cpp/Portability.hh"
#ifdef LOG4CPP_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <iostream>
#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#ifdef LOG4CPP_HAVE_SYSLOG
#include "log4cpp/SyslogAppender.hh"
#endif
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"

int main(int argc, char** argv) {
	log4cpp::Appender* appender;
#ifdef LOG4CPP_HAVE_SYSLOG
	log4cpp::SyslogAppender* syslogAppender;

	syslogAppender = new log4cpp::SyslogAppender("syslog", "log4cpp");
#else
	log4cpp::Appender* syslogAppender;

	syslogAppender = new log4cpp::OstreamAppender("syslogdummy", &std::cout);
#endif

	if (argc < 2) {
		appender = new log4cpp::OstreamAppender("default", &std::cout);
	} else {
		appender = new log4cpp::FileAppender("default", argv[1]);
	}

	syslogAppender->setLayout(new log4cpp::BasicLayout());
	appender->setLayout(new log4cpp::BasicLayout());

	log4cpp::Category& root = log4cpp::Category::getRoot();
	root.addAppender(syslogAppender);
	root.setPriority(log4cpp::Priority::ERROR);

	log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
	sub1.addAppender(appender);

	log4cpp::Category& sub2 = log4cpp::Category::getInstance(std::string("sub1.sub2"));

	log4cpp::NDC::push(std::string("ndc1"));

	std::cout << " root prio = " << root.getPriority() << std::endl;
	std::cout << " sub1 prio = " << sub1.getPriority() << std::endl;
	std::cout << " sub2 prio = " << sub2.getPriority() << std::endl;

	root.error("root error");
	root.warn("root warn");
	sub1.error("sub1 error");
	sub1.warn("sub1 warn");
	sub2.error("sub2 error");
	sub2.warn("sub2 warn");

	sub1.setPriority(log4cpp::Priority::INFO);
	std::cout << " root prio = " << root.getPriority() << std::endl;
	std::cout << " sub1 prio = " << sub1.getPriority() << std::endl;
	std::cout << " sub2 prio = " << sub2.getPriority() << std::endl;

	std::cout << "priority info" << std::endl;
	root.error("root error");
	root.warn("root warn");
	sub1.error("sub1 error");
	sub1.warn("sub1 warn");
	sub2.error("sub2 error");
	sub2.warn("sub2 warn");

	sub2.warnStream() << "streamed warn";

	sub2 << log4cpp::Priority::WARN << "warn2" << " warn3" <<
		log4cpp::CategoryStream::ENDLINE << " warn4";

	{
		for(int i = 0; i < 10000; i++) {
			char ndc2[20];
			sprintf(ndc2, "i=%d", i);
			log4cpp::NDC::push(ndc2);
			sub1.info("%s%d", "i = ", i);
			if ((i % 10) == 0) {
				sub1.log(log4cpp::Priority::NOTICE, "reopen log");
				if (log4cpp::Appender::reopenAll()) {
					sub1.info("log reopened");
				} else {
					sub1.warn("could not reopen log");
				}
			}
#ifndef WIN32
			sleep(1);
#endif
			log4cpp::NDC::pop();
		}
	}
}
<commit_msg>have main() return 0; (bug #718941)<commit_after>#include <stdio.h>
#include "log4cpp/Portability.hh"
#ifdef LOG4CPP_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <iostream>
#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#ifdef LOG4CPP_HAVE_SYSLOG
#include "log4cpp/SyslogAppender.hh"
#endif
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"

int main(int argc, char** argv) {
	log4cpp::Appender* appender;
#ifdef LOG4CPP_HAVE_SYSLOG
	log4cpp::SyslogAppender* syslogAppender;

	syslogAppender = new log4cpp::SyslogAppender("syslog", "log4cpp");
#else
	log4cpp::Appender* syslogAppender;

	syslogAppender = new log4cpp::OstreamAppender("syslogdummy", &std::cout);
#endif

	if (argc < 2) {
		appender = new log4cpp::OstreamAppender("default", &std::cout);
	} else {
		appender = new log4cpp::FileAppender("default", argv[1]);
	}

	syslogAppender->setLayout(new log4cpp::BasicLayout());
	appender->setLayout(new log4cpp::BasicLayout());

	log4cpp::Category& root = log4cpp::Category::getRoot();
	root.addAppender(syslogAppender);
	root.setPriority(log4cpp::Priority::ERROR);

	log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
	sub1.addAppender(appender);

	log4cpp::Category& sub2 = log4cpp::Category::getInstance(std::string("sub1.sub2"));

	log4cpp::NDC::push(std::string("ndc1"));

	std::cout << " root prio = " << root.getPriority() << std::endl;
	std::cout << " sub1 prio = " << sub1.getPriority() << std::endl;
	std::cout << " sub2 prio = " << sub2.getPriority() << std::endl;

	root.error("root error");
	root.warn("root warn");
	sub1.error("sub1 error");
	sub1.warn("sub1 warn");
	sub2.error("sub2 error");
	sub2.warn("sub2 warn");

	sub1.setPriority(log4cpp::Priority::INFO);
	std::cout << " root prio = " << root.getPriority() << std::endl;
	std::cout << " sub1 prio = " << sub1.getPriority() << std::endl;
	std::cout << " sub2 prio = " << sub2.getPriority() << std::endl;

	std::cout << "priority info" << std::endl;
	root.error("root error");
	root.warn("root warn");
	sub1.error("sub1 error");
	sub1.warn("sub1 warn");
	sub2.error("sub2 error");
	sub2.warn("sub2 warn");

	sub2.warnStream() << "streamed warn";

	sub2 << log4cpp::Priority::WARN << "warn2" << " warn3" <<
		log4cpp::CategoryStream::ENDLINE << " warn4";

	{
		for(int i = 0; i < 10000; i++) {
			char ndc2[20];
			sprintf(ndc2, "i=%d", i);
			log4cpp::NDC::push(ndc2);
			sub1.info("%s%d", "i = ", i);
			if ((i % 10) == 0) {
				sub1.log(log4cpp::Priority::NOTICE, "reopen log");
				if (log4cpp::Appender::reopenAll()) {
					sub1.info("log reopened");
				} else {
					sub1.warn("could not reopen log");
				}
			}
#ifndef WIN32
			sleep(1);
#endif
			log4cpp::NDC::pop();
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>//macro illustrating how to animate a picture using a Timer
Double_t pi;
TF2 *f2;
Float_t t = 0;
Float_t phi = 30;
void anim()
{
   gStyle->SetFrameFillColor(42);
   TCanvas *c1 = new TCanvas("c1");
   c1->SetFillColor(17);
   pi = TMath::Pi();
   f2 = new TF2("f2","sin(2*x)*sin(2*y)*[0]",0,pi,0,pi);
   f2->SetParameter(0,1);
   f2->SetNpx(15);
   f2->SetNpy(15);
   f2->SetMaximum(1);
   f2->SetMinimum(-1);
   f2->Draw("surf1");
   TTimer *timer = new TTimer(20);
   timer->SetCommand("Animate()");
   timer->TurnOn();
}
void Animate()
{
   t += 0.05*pi;
   f2->SetParameter(0,TMath::Cos(t));
   phi += 2;
   gPad->SetPhi(phi);
   gPad->Modified();
   gPad->Update();
}
<commit_msg>Protect the script in case the canvas is deleted while the script is running.<commit_after>//macro illustrating how to animate a picture using a Timer
Double_t pi;
TF2 *f2;
Float_t t = 0;
Float_t phi = 30;
void anim()
{
   gStyle->SetFrameFillColor(42);
   TCanvas *c1 = new TCanvas("c1");
   c1->SetFillColor(17);
   pi = TMath::Pi();
   f2 = new TF2("f2","sin(2*x)*sin(2*y)*[0]",0,pi,0,pi);
   f2->SetParameter(0,1);
   f2->SetNpx(15);
   f2->SetNpy(15);
   f2->SetMaximum(1);
   f2->SetMinimum(-1);
   f2->Draw("surf1");
   TTimer *timer = new TTimer(20);
   timer->SetCommand("Animate()");
   timer->TurnOn();
}
void Animate()
{
   if (!gROOT->GetListOfCanvases()->FindObject("c1")) return; //just in case the canvas has been deleted
   t += 0.05*pi;
   f2->SetParameter(0,TMath::Cos(t));
   phi += 2;
   gPad->SetPhi(phi);
   gPad->Modified();
   gPad->Update();
}
<|endoftext|>


<commit_before>//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and statement subclasses.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/IdentifierTable.h"
using namespace clang;

static struct StmtClassNameTable {
  int enumValue;
  const char *className;
  unsigned counter;
  unsigned size;
} sNames[] = {
#define STMT(N, CLASS, PARENT) { N, #CLASS, 0, sizeof(CLASS) },
#include "clang/AST/StmtNodes.def"
  { 0, 0, 0, 0 }
};

const char *Stmt::getStmtClassName() const {
  for (int i = 0; sNames[i].className; i++) {
    if (sClass == sNames[i].enumValue)
      return sNames[i].className;
  }
  return 0; // should never happen....
}

void Stmt::PrintStats() {
  unsigned sum = 0;
  fprintf(stderr, "*** Stmt/Expr Stats:\n");
  for (int i = 0; sNames[i].className; i++) {
    sum += sNames[i].counter;
  }
  fprintf(stderr, "  %d stmts/exprs total.\n", sum);
  sum = 0;
  for (int i = 0; sNames[i].className; i++) {
    fprintf(stderr, "    %d %s, %d each (%d bytes)\n",
      sNames[i].counter, sNames[i].className, sNames[i].size, sNames[i].counter*sNames[i].size);
    sum += sNames[i].counter*sNames[i].size;
  }
  fprintf(stderr, "Total bytes = %d\n", sum);
}

void Stmt::addStmtClass(StmtClass s) {
  for (int i = 0; sNames[i].className; i++) {
    if (s == sNames[i].enumValue)
      sNames[i].counter++;
  }
}

static bool StatSwitch = false;

bool Stmt::CollectingStats(bool enable) {
  if (enable) StatSwitch = true;
	return StatSwitch;
}

const char *LabelStmt::getName() const {
  return getID()->getName();
}

//===----------------------------------------------------------------------===//
//  Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//

// DeclStmt
Stmt::child_iterator DeclStmt::child_begin() { return NULL; }
Stmt::child_iterator DeclStmt::child_end() { return NULL; }

// NullStmt
Stmt::child_iterator NullStmt::child_begin() { return NULL; }
Stmt::child_iterator NullStmt::child_end() { return NULL; }

// CompoundStmt
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }

// SwitchCase
Stmt::child_iterator SwitchCase::child_begin() { return &SubStmt; }
Stmt::child_iterator SwitchCase::child_end() { return child_begin()+1; }

// LabelStmt
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return child_begin()+1; }

// IfStmt
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// SwitchStmt
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// WhileStmt
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ForStmt
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// GotoStmt
Stmt::child_iterator GotoStmt::child_begin() { return NULL; }
Stmt::child_iterator GotoStmt::child_end() { return NULL; }

// IndirectGotoStmt
Stmt::child_iterator IndirectGotoStmt::child_begin() {
  return reinterpret_cast<Stmt**>(&Target);
}

Stmt::child_iterator IndirectGotoStmt::child_end() { return child_begin()+1; }

// ContinueStmt
Stmt::child_iterator ContinueStmt::child_begin() { return NULL; }
Stmt::child_iterator ContinueStmt::child_end() { return NULL; }

// BreakStmt
Stmt::child_iterator BreakStmt::child_begin() { return NULL; }
Stmt::child_iterator BreakStmt::child_end() { return NULL; }

// ReturnStmt
Stmt::child_iterator ReturnStmt::child_begin() {
  return reinterpret_cast<Stmt**>(&RetExpr);
}

Stmt::child_iterator ReturnStmt::child_end() { return child_begin()+1; }

<commit_msg>rename sNames -> StmtClassInfo.  Make lookups constant time.<commit_after>//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Chris Lattner and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and statement subclasses.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/IdentifierTable.h"
using namespace clang;

static struct StmtClassNameTable {
  const char *Name;
  unsigned Counter;
  unsigned Size;
} StmtClassInfo[Stmt::lastExprConstant];

static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
  static bool Initialized = false;
  if (Initialized)
    return StmtClassInfo[E];

  // Intialize the table on the first use.
  Initialized = true;
#define STMT(N, CLASS, PARENT) \
  StmtClassInfo[N].Name = #CLASS; \
  StmtClassInfo[N].Size = sizeof(CLASS);
#include "clang/AST/StmtNodes.def"

  return StmtClassInfo[E];
}

const char *Stmt::getStmtClassName() const {
  return getStmtInfoTableEntry(sClass).Name;
}

void Stmt::PrintStats() {
  // Ensure the table is primed.
  getStmtInfoTableEntry(Stmt::NullStmtClass);

  unsigned sum = 0;
  fprintf(stderr, "*** Stmt/Expr Stats:\n");
  for (int i = 0; i != Stmt::lastExprConstant; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    sum += StmtClassInfo[i].Counter;
  }
  fprintf(stderr, "  %d stmts/exprs total.\n", sum);
  sum = 0;
  for (int i = 0; i != Stmt::lastExprConstant; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    fprintf(stderr, "    %d %s, %d each (%d bytes)\n",
            StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
            StmtClassInfo[i].Size,
            StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
    sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
  }
  fprintf(stderr, "Total bytes = %d\n", sum);
}

void Stmt::addStmtClass(StmtClass s) {
  ++getStmtInfoTableEntry(s).Counter;
}

static bool StatSwitch = false;

bool Stmt::CollectingStats(bool enable) {
  if (enable) StatSwitch = true;
  return StatSwitch;
}

const char *LabelStmt::getName() const {
  return getID()->getName();
}

//===----------------------------------------------------------------------===//
//  Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//

// DeclStmt
Stmt::child_iterator DeclStmt::child_begin() { return NULL; }
Stmt::child_iterator DeclStmt::child_end() { return NULL; }

// NullStmt
Stmt::child_iterator NullStmt::child_begin() { return NULL; }
Stmt::child_iterator NullStmt::child_end() { return NULL; }

// CompoundStmt
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }

// SwitchCase
Stmt::child_iterator SwitchCase::child_begin() { return &SubStmt; }
Stmt::child_iterator SwitchCase::child_end() { return child_begin()+1; }

// LabelStmt
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return child_begin()+1; }

// IfStmt
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// SwitchStmt
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// WhileStmt
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ForStmt
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// GotoStmt
Stmt::child_iterator GotoStmt::child_begin() { return NULL; }
Stmt::child_iterator GotoStmt::child_end() { return NULL; }

// IndirectGotoStmt
Stmt::child_iterator IndirectGotoStmt::child_begin() {
  return reinterpret_cast<Stmt**>(&Target);
}

Stmt::child_iterator IndirectGotoStmt::child_end() { return child_begin()+1; }

// ContinueStmt
Stmt::child_iterator ContinueStmt::child_begin() { return NULL; }
Stmt::child_iterator ContinueStmt::child_end() { return NULL; }

// BreakStmt
Stmt::child_iterator BreakStmt::child_begin() { return NULL; }
Stmt::child_iterator BreakStmt::child_end() { return NULL; }

// ReturnStmt
Stmt::child_iterator ReturnStmt::child_begin() {
  return reinterpret_cast<Stmt**>(&RetExpr);
}

Stmt::child_iterator ReturnStmt::child_end() { return child_begin()+1; }

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Deepsea
 *
 * This software may be modified and distributed under
 * the terms of the MIT license.  See the LICENSE file
 * for details.
 *
 */

#include <iostream>
#include <memory>
#include <deque>

#include "cactus-basic.hpp"

namespace cactus_stack {
  namespace basic {

    /*------------------------------*/
    /* Frame */

    class frame {
    public:
      int v;
    };

    /* Frame */
    /*------------------------------*/

    /*------------------------------*/
    /* Trace */

    using machine_stack_type = stack_type;
    using reference_stack_type = std::deque<frame>;

    using fork_result_tag = enum {
      Fork_result_none, Fork_result_some
    };

    using fork_result_type = struct {
      fork_result_tag tag;
      reference_stack_type s1, s2;
      frame f1, f2;
    };

    bool is_marked(frame& f) {
      return f.s.plt == Parent_link_async;
    }

    fork_result_type fork_mark(reference_stack_type& s) {
      fork_result_type r;
      constexpr int not_found = -1;
      size_t k = not_found;
      auto nb_frames = s.size();
      for (size_t i = 0; i < nb_frames; i++) {
        if (is_marked(s[i])) {
          k = i;
          break;
        }
      }
      if (k == not_found) {
        r.tag = Fork_result_none;
        return r;
      }
      reference_stack_type t1(s.begin(), s.begin() + k);
      reference_stack_type t2(s.begin() + k, s.end());
      r.tag = Fork_result_some;
      r.s1 = t1;
      r.s2 = t2;
      r.s1.pop_back();
      r.s2.pop_front();
      r.f1 = t1.back();
      r.f2 = t2.front();
      return r;
    }

    using trace_tag_type = enum {
      Trace_push_back, Trace_pop_back,
      Trace_fork_mark,
      Trace_nil
    };

    struct trace_struct {
      trace_tag_type tag;
      struct {
        frame f;
        std::unique_ptr<struct trace_struct> k;
      } push_back;
      struct {
        std::unique_ptr<struct trace_struct> k;
      } pop_back;
      struct fork_mark_struct {
        std::unique_ptr<struct trace_struct> k1;
        std::unique_ptr<struct trace_struct> k2;
      } fork_mark;
    };

    using trace_type = struct trace_struct;

    trace_type mk_push_back(frame f) {
      trace_type t;
      t.tag = Trace_push_back;
      t.push_back.f = f;
      return t;
    }

    trace_type mk_pop_back() {
      trace_type t;
      t.tag = Trace_pop_back;
      return t;
    }

    trace_type mk_fork_mark() {
      trace_type t;
      t.tag = Trace_fork_mark;
      return t;
    }

    using thread_config_type = struct {
      trace_type t;
      reference_stack_type rs; // reference stack
      machine_stack_type ms;
    };

    using machine_tag_type = enum {
      Machine_fork_mark, Machine_thread, Machine_stuck
    };

    using machine_config_type = struct machine_config_struct {
      machine_tag_type tag;
      struct {
        std::unique_ptr<struct machine_config_struct> m1;
        std::unique_ptr<struct machine_config_struct> m2;
      } fork_mark;
      thread_config_type thread;
    };

    /* Trace */
    /*------------------------------*/

  } // end namespace
} // end namespace

int main(int argc, const char * argv[]) {
  std::cout << "Hello, World!\n";
  return 0;
}
<commit_msg>Working on basic cactus stack<commit_after>/*
 * Copyright (c) 2017 Deepsea
 *
 * This software may be modified and distributed under
 * the terms of the MIT license.  See the LICENSE file
 * for details.
 *
 */

#include <iostream>
#include <memory>
#include <deque>

#include "cactus-basic.hpp"

namespace cactus_stack {
  namespace basic {

    /*------------------------------*/
    /* Frame */

    class frame {
    public:
      int v;
      parent_link_type plt;
    };

    /* Frame */
    /*------------------------------*/

    /*------------------------------*/
    /* Trace */

    using machine_stack_type = stack_type;
    using reference_stack_type = std::deque<frame>;

    using fork_result_tag = enum {
      Fork_result_none, Fork_result_some
    };

    using fork_result_type = struct {
      fork_result_tag tag;
      reference_stack_type s1, s2;
      frame f1, f2;
    };

    bool is_marked(frame& f) {
      return f.plt == Parent_link_async;
    }

    fork_result_type fork_mark(reference_stack_type& s) {
      fork_result_type r;
      constexpr int not_found = -1;
      size_t k = not_found;
      auto nb_frames = s.size();
      for (size_t i = 0; i < nb_frames; i++) {
        if (is_marked(s[i])) {
          k = i;
          break;
        }
      }
      if (k == not_found) {
        r.tag = Fork_result_none;
        return r;
      }
      reference_stack_type t1(s.begin(), s.begin() + k);
      reference_stack_type t2(s.begin() + k, s.end());
      r.tag = Fork_result_some;
      r.s1 = t1;
      r.s2 = t2;
      r.s1.pop_back();
      r.s2.pop_front();
      r.f1 = t1.back();
      r.f2 = t2.front();
      return r;
    }

    using trace_tag_type = enum {
      Trace_push_back, Trace_pop_back,
      Trace_fork_mark,
      Trace_nil
    };

    struct trace_struct {
      trace_tag_type tag;
      struct {
        frame f;
        std::shared_ptr<struct trace_struct> k;
      } push_back;
      struct {
        std::shared_ptr<struct trace_struct> k;
      } pop_back;
      struct fork_mark_struct {
        std::shared_ptr<struct trace_struct> k1;
        std::shared_ptr<struct trace_struct> k2;
      } fork_mark;
    };

    using trace_type = struct trace_struct;

    trace_type* mk_push_back(frame f) {
      trace_type* t = new trace_type;
      t->tag = Trace_push_back;
      t->push_back.f = f;
      return t;
    }

    trace_type* mk_pop_back() {
      trace_type* t = new trace_type;
      t->tag = Trace_pop_back;
      return t;
    }

    trace_type* mk_fork_mark() {
      trace_type* t = new trace_type;
      t->tag = Trace_fork_mark;
      return t;
    }

    using thread_config_type = struct {
      trace_type t;
      reference_stack_type rs; // reference stack
      machine_stack_type ms;
    };

    using machine_tag_type = enum {
      Machine_fork_mark, Machine_thread, Machine_stuck
    };

    using machine_config_type = struct machine_config_struct {
      machine_tag_type tag;
      struct {
        std::shared_ptr<struct machine_config_struct> m1;
        std::shared_ptr<struct machine_config_struct> m2;
      } fork_mark;
      thread_config_type thread;
    };

    template <class Coin_flip>
    machine_config_type step(const Coin_flip& coin_flip, machine_config_type& m) {
      machine_config_type n;
      n.tag = Machine_stuck;
      switch (m.tag) {
        case Machine_fork_mark: {
          n.tag = Machine_fork_mark;
          if (coin_flip()) {
            *n.fork_mark.m1 = step(coin_flip, *m.fork_mark.m1);
            n.fork_mark.m2.swap(m.fork_mark.m2);
          } else {
            n.fork_mark.m1.swap(m.fork_mark.m1);
            *n.fork_mark.m2 = step(coin_flip, *m.fork_mark.m2);
          }
          break;
        }
        case Machine_thread: {
          thread_config_type& tc_m = m.thread;
          thread_config_type& tc_n = n.thread;
          switch (tc_m.t.tag) {
            case Trace_fork_mark: {
              n.tag = Machine_fork_mark;
              auto mp = fork_mark(tc_m.ms);
              auto rp = fork_mark(tc_m.rs);
              reference_stack_type rs1, rs2;
              if (rp.tag == Fork_result_some) {
                rs1 = rp.s1;
                rs1.push_back(rp.f1);
                rs2 = rp.s2;
                rs2.push_back(rp.f2);
              } else {
                rs1 = tc_m.rs;
              }
              n.fork_mark.m1.reset(new machine_config_type);
              n.fork_mark.m2.reset(new machine_config_type);
              machine_config_type& m1 = *n.fork_mark.m1;
              machine_config_type& m2 = *n.fork_mark.m2;
              m1.tag = Machine_thread;
              m1.thread.t = std::move(*tc_m.t.fork_mark.k1);
              m1.thread.ms = mp.first;
              m1.thread.rs = rs1;
              m2.tag = Machine_thread;
              m2.thread.t = std::move(*tc_m.t.fork_mark.k2);
              m2.thread.ms = mp.second;
              m2.thread.rs = rs2;
              break;
            }
            case Trace_push_back: {
              frame f = tc_m.t.push_back.f;
              n.tag = Machine_thread;
              tc_n.rs = tc_m.rs;
              tc_n.rs.push_back(f);
              auto init_fn = [&] (char* p) {
                new ((frame*)p) frame(f);
              };
              tc_n.ms = push_back<sizeof(frame),decltype(init_fn)>(tc_m.ms, f.plt, init_fn);
              break;
            }
            case Trace_pop_back: {
              n.tag = Machine_thread;
              tc_n.rs = tc_m.rs;
              tc_n.rs.pop_back();
              auto destr_fn = [&] (char* p) {
                ((frame*)(p))->~frame();
              };
              tc_n.ms = pop_back(tc_m.ms, destr_fn);
              break;
            }
            default: {
              assert(false); // todo
            }
          }
          break;
        }
        case Machine_stuck: {
          break;
        }
        default: {
          break;
        }
      }
      return n;
    }

    /* Trace */
    /*------------------------------*/

    void ex1() {
      frame f;
      f.v = 123;
      auto t2 = mk_push_back(f);
      t2->push_back.k.reset(mk_pop_back());
      machine_config_type m;
      step([&] {
        return rand() % 2 == 0;
      }, m);
    }

  } // end namespace
} // end namespace

int main(int argc, const char * argv[]) {
  std::cout << "starting\n";
  cactus_stack::basic::ex1();
  std::cout << "finished\n";
  return 0;
}
<|endoftext|>