<commit_before>#define SPDLOG_DEBUG_ON
// enable logging macros

#include <capnp/message.h>
#include <kj/io.h>

#include <commelec-api/serialization.hpp>
#include <commelec-api/schema.capnp.h>
#include <commelec-api/hlapi-internal.hpp>
#include <commelec-api/sender-policies.hpp>
#include <commelec-api/json.hpp>

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>

#include <spdlog/spdlog.h>
// logging framework

#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <boost/filesystem.hpp>

#include <iostream>
#include <string>
#include <unordered_map>

using boost::asio::ip::udp;
using PortNumberType = unsigned short;
using AgentIdType = uint32_t;

using namespace boost::filesystem;

enum class Resource { battery, pv, fuelcell, discrete, discreteUnif };
using ResourceMap = std::unordered_map<std::string, Resource> ;

enum {
  networkBufLen = 2048, // length of data buffer for incoming requests
  maxUDPsize = 65536,
  maxRetransmissions = 10,
  interPacketSendDelay_ms = 2
};

void createBattAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto Srated = d["Srated"].GetDouble();
  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();
  auto Qimp = d["Qimp"].GetDouble();

  _BatteryAdvertisement(msg.initAdvertisement(), Pmin, Pmax, Srated, coeffP,
                        coeffPsquared, 0.0, Pimp, Qimp);
  return;
}

void createDiscreteAdv(msg::Message::Builder msg, rapidjson::Document &d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto error = d["error"].GetDouble();

  std::vector<double> points;
  auto &pointList = d["points"];
  for (auto itr = pointList.Begin(); itr != pointList.End(); ++itr)
    points.push_back(itr->GetDouble());

  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();

  _realDiscreteDeviceAdvertisement(msg.initAdvertisement(), Pmin, Pmax, points,
                                   error, coeffPsquared, coeffP, Pimp);
  return;
}

void createDiscreteUnifAdv(msg::Message::Builder msg, rapidjson::Document &d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto stepsize = d["stepsize"].GetDouble();
  auto error = d["error"].GetDouble();

  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();

  _uniformRealDiscreteDeviceAdvertisement(msg.initAdvertisement(), Pmin, Pmax,
                                          stepsize, error, coeffPsquared,
                                          coeffP, Pimp);
  return;
}

void createFuelCellAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  createBattAdv(msg, d);
}

void createPVAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  auto Pmax = d["Pmax"].GetDouble();
  auto Pdelta = d["Pdelta"].GetDouble();
  auto Srated = d["Srated"].GetDouble();

  auto cosPhi = d["cosPhi"].GetDouble(); // power factor (PF) = cos(phi)
  auto tanPhi = std::sqrt( 1.0 - std::pow(cosPhi,2))/cosPhi; // tan(phi) = sqrt(1 - PF^2) / PF

  auto a_pv = d["a_pv"].GetDouble();
  auto b_pv = d["b_pv"].GetDouble();

  auto Pimp = d["Pimp"].GetDouble();
  auto Qimp = d["Qimp"].GetDouble();

  _PVAdvertisement(msg.initAdvertisement(), Srated, Pmax, Pdelta, tanPhi, a_pv,
                   b_pv, Pimp, Qimp);

  return;
}

// The "packing"-policy lets a user of the class choose between packed
// serialisation and de-serialisation (default) or a variant that omits packing
// See also: https://capnproto.org/encoding.html#packing
// The PackedSerialization class can be found in "messaging/SenderPolicies.hpp"
template <typename PackingPolicy = PackedSerialization>
class CommelecDaemon : private PackingPolicy {
  using PackingPolicy::serializeAndAsyncSend;
  using typename PackingPolicy::CapnpReader;

public:
  CommelecDaemon(boost::asio::io_service &io_service,AgentIdType agentId, Resource resourceType,
                 PortNumberType localhost_listen_port,
                 PortNumberType network_listen_port,
                 const boost::asio::ip::udp::endpoint &local_dest_endpoint,
                 const boost::asio::ip::udp::endpoint &network_dest_endpoint)
      : _agentId(agentId), _resourceType(resourceType), _strand(io_service),
        _local_socket(io_service,
                      udp::endpoint(udp::v4(), localhost_listen_port)),
        _network_socket(io_service,
                        udp::endpoint(udp::v4(), network_listen_port)),
        _local_dest_endpoint(local_dest_endpoint),
        _network_dest_endpoint(network_dest_endpoint), _timer(io_service),
        logger(spdlog::stdout_logger_mt("console"))

  {
    boost::asio::spawn(_strand,
                [this](boost::asio::yield_context yield) { listenGAside(yield); });
    boost::asio::spawn(_strand,
                [this](boost::asio::yield_context yield) { listenRAside(yield); });

    logger->set_level(spdlog::level::debug);
    SPDLOG_DEBUG(logger, "Started coroutines");
    // run listeners as coroutines
  }

private:
  void listenGAside(boost::asio::yield_context yield) {
    // listen on the 'network side' for Cap'n Proto-encoded requests sent by a
    // GA

    using namespace rapidjson;
    for (;;) { // run endlessly

      auto asio_buffer = boost::asio::buffer(_network_data, networkBufLen);
      boost::asio::ip::udp::endpoint sender_endpoint;
      size_t bytes_received =
          _network_socket.async_receive_from(asio_buffer, sender_endpoint, yield);
      // wait for incoming packet

      CapnpReader reader(asio_buffer);
      msg::Message::Reader msg = reader.getMessage();
      if (!msg.hasRequest())
        throw;
      auto req = msg.getRequest();
      // parse Capnp

      SPDLOG_DEBUG(logger, "Request received from GA");

      Document d;
      d.SetObject();

      Value spValid;
      auto valid = req.hasSetpoint();
      spValid.SetBool(valid);

      double P, Q;
      if (valid) {
        auto sp = req.getSetpoint();
        P = sp[0];
        Q = sp[1];
      }

      auto &allocator = d.GetAllocator();
      // must pass an allocator when the object may need to allocate memory

      d.AddMember("setpointValid", spValid, allocator);
      d.AddMember("senderId", msg.getAgentId(), allocator);
      d.AddMember("P", P, allocator);
      d.AddMember("Q", Q, allocator);
      // construct the JSON object

      StringBuffer buffer;
      Writer<StringBuffer> writer(buffer);
      d.Accept(writer);
      std::string payload = buffer.GetString();
      _local_socket.async_send_to(boost::asio::buffer(payload), _local_dest_endpoint,
                                    yield);
      // flatten to string and send packet
    }
  }
  void listenRAside(boost::asio::yield_context yield) {
    // listen for JSON-encoded advertisement-parameters from the RA

    using namespace rapidjson;
    for (;;) { // run endlessly

      auto asio_buffer = boost::asio::buffer(_local_data, maxUDPsize);
      boost::asio::ip::udp::endpoint sender_endpoint;
      size_t bytes_received = _local_socket.async_receive_from(asio_buffer, sender_endpoint, yield);
      // wait for incoming packet

      SPDLOG_DEBUG(logger, "Packet received from RA, bytes: {}", bytes_received);

      Document d;
      _local_data[bytes_received]=0; // terminate data as C-string
      d.Parse(reinterpret_cast<const char*>(_local_data));
      // parse JSON

      auto msg = _builder.initRoot<msg::Message>();
      msg.setAgentId(_agentId);
      // make advertisement, depending on which resource

      switch (_resourceType){
        case Resource::pv:
          createPVAdv(msg,d);
          break;

        case Resource::fuelcell:
          createFuelCellAdv(msg,d);
          break;

        case Resource::battery:
          createBattAdv(msg,d);
          break;

        case Resource::discrete:
          createDiscreteAdv(msg,d);
          break;

        case Resource::discreteUnif:
          createDiscreteAdv(msg,d);
          break;

      }

      serializeAndAsyncSend(_builder, _network_socket, _network_dest_endpoint,yield);
      // send packet

    }
  }

  //##################
  // class attributes
  //##################

  AgentIdType _agentId;
  Resource _resourceType;

  boost::asio::io_service::strand _strand;
  boost::asio::ip::udp::socket _local_socket;
  boost::asio::ip::udp::socket _network_socket;
  boost::asio::ip::udp::endpoint _network_dest_endpoint;
  boost::asio::ip::udp::endpoint _local_dest_endpoint;
  boost::asio::high_resolution_timer _timer;
  // asio stuff

  capnp::byte _local_data[maxUDPsize]; //2^16 bytes (max UDP packet size is 65,507 bytes)
  capnp::byte _network_data[networkBufLen];
  // persistent arrays for storing incoming udp packets

  capnp::MallocMessageBuilder _builder;
  // builder for storing outgoing (repeated) packets

  std::shared_ptr<spdlog::logger> logger;
};

udp::endpoint make_endpoint(std::string ip, int portnum) {
  return udp::endpoint(boost::asio::ip::address::from_string(ip), portnum);
}

void generateDefaultConfiguration(const char *configFile){
      // generate a default configuration and write it to disk

      rapidjson::Document d;
      d.SetObject();
      auto &allocator = d.GetAllocator();
      // init JSON object

      d.AddMember("resource-type", "battery", allocator);
      d.AddMember("agent-id", 1000, allocator);
      d.AddMember("GA-ip", "127.0.0.1", allocator);
      d.AddMember("GA-port", 12345, allocator);
      d.AddMember("RA-ip", "127.0.0.1", allocator);
      d.AddMember("RA-port", 12342, allocator);
      d.AddMember("listenport-RA-side", 12340, allocator);
      d.AddMember("listenport-GA-side", 12341, allocator);
      // populate JSON object

      writeJSONfile(configFile, d);
      // write JSON object to disk
}

int commandLineParser(int argc, char *argv[], std::string& configFile, ResourceMap& resources) {
  // This function handles command line arguments:
  //   * no command line arguments
  //   * '--generate' option
  //   * '--list-resouces' option
  //   * config file as argument
  //   # malformed arguments (i.e., more than one cl argument)
  //
  //   possibly updates configFile pointer
  //
  //   returns:
  //     false - some error occurred, program should terminate
  //     true  - configFile contains valid filename

  using std::cout;
  using std::endl;

  if (argc == 2) {
    if (std::string(argv[1]) == "--generate") {
      if (exists(configFile)) {

        cout << "Attempting to create '" << configFile
             << "', but that file already exists. Please remove that one first."
             << endl;
        return -1;
      }
      cout << "Generating configuration file... (This file can "
              "be edited by hand)" << endl;

      generateDefaultConfiguration(configFile.c_str());

      cout << "Done." << endl;
      return -1;
    }
    else if (std::string(argv[1]) == "--list-resources") {
      cout << "Available resource types:" << endl;
      for(auto& res: resources)
        cout << res.first << endl;
      return -1;

    } else { // command line arg is not an option
      configFile = (argv[1]);
      if (std::string(configFile) == "-")
        // read config from std input
        return 1;
      if (!exists(configFile) || !is_regular_file(configFile)) {
        cout << "Configuration file '" << configFile << "' could not be found."
             << endl;
        return -1;
      }
      return 0;
    }
  } else {
    cout << "Usage: " << argv[0] << " [config file]" << endl << endl;
    cout << "Other options:" << endl;
    cout << argv[0] << " -                    (read configuration from standard input)" << endl;
    cout << argv[0] << " --generate           (generates a default configuration)" << endl;
    cout << argv[0] << " --list-resources     (lists available resources)" << endl;
    return -1;
  }
}

// main function
int main(int argc, char *argv[]) {

  ResourceMap resources({{"pv", Resource::pv},
                         {"battery", Resource::battery},
                         {"fuelcell", Resource::fuelcell},
                         {"discrete-uniform", Resource::discreteUnif},
                         {"discrete", Resource::discrete}});

  boost::asio::io_service io_service;
  // needed for ASIO's eventloop

  auto configFile = std::string("daemon-cfg.json");
  auto status = commandLineParser(argc, argv, configFile, resources);
  // possibly updates 'configFile' filename

  rapidjson::Document cfg;
  switch (status) {
  case 0:
    cfg = readJSONfile(configFile.c_str());
    break;
  case 1:
    cfg = readJSONstdin();
    break;
  default:
    return status;
  }
  // read command line parameters

  if (!cfg.IsObject()) {
    std::cout << "Malformed JSON object in configuration file" << std::endl;
    return -1;
  }
  // read the configuration parameters from disk

  try {
    CommelecDaemon<> daemon(
        io_service, getInt(cfg, "agent-id"),
        resources.at(getString(cfg, "resource-type")),
        static_cast<PortNumberType>(getInt(cfg, "listenport-RA-side")),
        static_cast<PortNumberType>(getInt(cfg, "listenport-GA-side")),
        make_endpoint(getString(cfg, "RA-ip"),
                      static_cast<PortNumberType>(getInt(cfg, "RA-port"))),
        make_endpoint(getString(cfg, "GA-ip"),
                      static_cast<PortNumberType>(getInt(cfg, "GA-port"))));
    //instantiate our main class, with the parameters as set by the user in the config file

    io_service.run();
    // run asio's event-loop; used for asynchronous network IO using coroutines

  } catch (std::runtime_error e) {
    std::cout << "Config error: '" << e.what() << "' missing" << std::endl;
    return -1;
  } catch (std::out_of_range e) {
    std::cout << "Config error - unknown resource type: "
              << getString(cfg, "resource-type") << std::endl;
    return -1;
  }
}

<commit_msg>Added custom option to daemon for low-level api usage<commit_after>#define SPDLOG_DEBUG_ON
// enable logging macros

#include <capnp/message.h>
#include <kj/io.h>

#include <commelec-api/serialization.hpp>
#include <commelec-api/schema.capnp.h>
#include <commelec-api/hlapi-internal.hpp>
#include <commelec-api/sender-policies.hpp>
#include <commelec-api/json.hpp>

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>

#include <spdlog/spdlog.h>
// logging framework

#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <boost/filesystem.hpp>

#include <iostream>
#include <string>
#include <unordered_map>

using boost::asio::ip::udp;
using PortNumberType = unsigned short;
using AgentIdType = uint32_t;

using namespace boost::filesystem;

enum class Resource { battery, pv, fuelcell, discrete, discreteUnif, custom };
using ResourceMap = std::unordered_map<std::string, Resource> ;

enum {
  networkBufLen = 2048, // length of data buffer for incoming requests
  maxUDPsize = 65536,
  maxRetransmissions = 10,
  interPacketSendDelay_ms = 2
};

void createBattAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto Srated = d["Srated"].GetDouble();
  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();
  auto Qimp = d["Qimp"].GetDouble();

  _BatteryAdvertisement(msg.initAdvertisement(), Pmin, Pmax, Srated, coeffP,
                        coeffPsquared, 0.0, Pimp, Qimp);
  return;
}

void createDiscreteAdv(msg::Message::Builder msg, rapidjson::Document &d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto error = d["error"].GetDouble();

  std::vector<double> points;
  auto &pointList = d["points"];
  for (auto itr = pointList.Begin(); itr != pointList.End(); ++itr)
    points.push_back(itr->GetDouble());

  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();

  _realDiscreteDeviceAdvertisement(msg.initAdvertisement(), Pmin, Pmax, points,
                                   error, coeffPsquared, coeffP, Pimp);
  return;
}

void createDiscreteUnifAdv(msg::Message::Builder msg, rapidjson::Document &d) {
  auto Pmin = d["Pmin"].GetDouble();
  auto Pmax = d["Pmax"].GetDouble();
  auto stepsize = d["stepsize"].GetDouble();
  auto error = d["error"].GetDouble();

  auto coeffP = d["coeffP"].GetDouble();
  auto coeffPsquared = d["coeffPsquared"].GetDouble();
  auto Pimp = d["Pimp"].GetDouble();

  _uniformRealDiscreteDeviceAdvertisement(msg.initAdvertisement(), Pmin, Pmax,
                                          stepsize, error, coeffPsquared,
                                          coeffP, Pimp);
  return;
}

void createFuelCellAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  createBattAdv(msg, d);
}

void createPVAdv(msg::Message::Builder msg, rapidjson::Document& d) {
  auto Pmax = d["Pmax"].GetDouble();
  auto Pdelta = d["Pdelta"].GetDouble();
  auto Srated = d["Srated"].GetDouble();

  auto cosPhi = d["cosPhi"].GetDouble(); // power factor (PF) = cos(phi)
  auto tanPhi = std::sqrt( 1.0 - std::pow(cosPhi,2))/cosPhi; // tan(phi) = sqrt(1 - PF^2) / PF

  auto a_pv = d["a_pv"].GetDouble();
  auto b_pv = d["b_pv"].GetDouble();

  auto Pimp = d["Pimp"].GetDouble();
  auto Qimp = d["Qimp"].GetDouble();

  _PVAdvertisement(msg.initAdvertisement(), Srated, Pmax, Pdelta, tanPhi, a_pv,
                   b_pv, Pimp, Qimp);

  return;
}

// The "packing"-policy lets a user of the class choose between packed
// serialisation and de-serialisation (default) or a variant that omits packing
// See also: https://capnproto.org/encoding.html#packing
// The PackedSerialization class can be found in "messaging/SenderPolicies.hpp"
template <typename PackingPolicy = PackedSerialization>
class CommelecDaemon : private PackingPolicy {
  using PackingPolicy::serializeAndAsyncSend;
  using typename PackingPolicy::CapnpReader;

public:
  CommelecDaemon(boost::asio::io_service &io_service,AgentIdType agentId, Resource resourceType,
                 PortNumberType localhost_listen_port,
                 PortNumberType network_listen_port,
                 const boost::asio::ip::udp::endpoint &local_dest_endpoint,
                 const boost::asio::ip::udp::endpoint &network_dest_endpoint)
      : _agentId(agentId), _resourceType(resourceType), _strand(io_service),
        _local_socket(io_service,
                      udp::endpoint(udp::v4(), localhost_listen_port)),
        _network_socket(io_service,
                        udp::endpoint(udp::v4(), network_listen_port)),
        _local_dest_endpoint(local_dest_endpoint),
        _network_dest_endpoint(network_dest_endpoint), _timer(io_service),
        logger(spdlog::stdout_logger_mt("console"))

  {
    boost::asio::spawn(_strand,
                [this](boost::asio::yield_context yield) { listenGAside(yield); });
    boost::asio::spawn(_strand,
                [this](boost::asio::yield_context yield) { listenRAside(yield); });

    logger->set_level(spdlog::level::debug);
    SPDLOG_DEBUG(logger, "Started coroutines");
    // run listeners as coroutines
  }

private:
  void listenGAside(boost::asio::yield_context yield) {
    // listen on the 'network side' for Cap'n Proto-encoded requests sent by a
    // GA

    using namespace rapidjson;
    for (;;) { // run endlessly

      auto asio_buffer = boost::asio::buffer(_network_data, networkBufLen);
      boost::asio::ip::udp::endpoint sender_endpoint;
      size_t bytes_received = _network_socket.async_receive_from(
          asio_buffer, sender_endpoint, yield);
      // wait for incoming packet

      if (_resourceType == Resource::custom) {

        // forward payload to client
        auto bytesWritten = _local_socket.async_send_to(
            asio_buffer, _local_dest_endpoint, yield);

      } else {

        CapnpReader reader(asio_buffer);
        msg::Message::Reader msg = reader.getMessage();
        if (!msg.hasRequest())
          throw;
        auto req = msg.getRequest();
        // parse Capnp

        SPDLOG_DEBUG(logger, "Request received from GA");

        Document d;
        d.SetObject();

        Value spValid;
        auto valid = req.hasSetpoint();
        spValid.SetBool(valid);

        double P, Q;
        if (valid) {
          auto sp = req.getSetpoint();
          P = sp[0];
          Q = sp[1];
        }

        auto &allocator = d.GetAllocator();
        // must pass an allocator when the object may need to allocate memory

        d.AddMember("setpointValid", spValid, allocator);
        d.AddMember("senderId", msg.getAgentId(), allocator);
        d.AddMember("P", P, allocator);
        d.AddMember("Q", Q, allocator);
        // construct the JSON object

        StringBuffer buffer;
        Writer<StringBuffer> writer(buffer);
        d.Accept(writer);
        std::string payload = buffer.GetString();
        _local_socket.async_send_to(boost::asio::buffer(payload),
                                    _local_dest_endpoint, yield);
        // flatten to string and send packet
      }
    }
  }
  void listenRAside(boost::asio::yield_context yield) {
    // listen for JSON-encoded advertisement-parameters from the RA

    using namespace rapidjson;
    for (;;) { // run endlessly

      auto asio_buffer = boost::asio::buffer(_local_data, maxUDPsize);
      boost::asio::ip::udp::endpoint sender_endpoint;
      size_t bytes_received = _local_socket.async_receive_from(asio_buffer, sender_endpoint, yield);
      // wait for incoming packet

      SPDLOG_DEBUG(logger, "Packet received from RA, bytes: {}", bytes_received);

      if (_resourceType == Resource::custom) {

        // forward payload (later, we will add transport-layer logic here)
        auto bytesWritten = _network_socket.async_send_to(asio_buffer, _network_dest_endpoint, yield);

      } else {

        Document d;
        _local_data[bytes_received] = 0; // terminate data as C-string
        d.Parse(reinterpret_cast<const char *>(_local_data));
        // parse JSON

        auto msg = _builder.initRoot<msg::Message>();
        msg.setAgentId(_agentId);
        // make advertisement, depending on which resource

        switch (_resourceType) {
        case Resource::pv:
          createPVAdv(msg, d);
          break;

        case Resource::fuelcell:
          createFuelCellAdv(msg, d);
          break;

        case Resource::battery:
          createBattAdv(msg, d);
          break;

        case Resource::discrete:
          createDiscreteAdv(msg, d);
          break;

        case Resource::discreteUnif:
          createDiscreteAdv(msg, d);
          break;

        default:
          break;
        }
        serializeAndAsyncSend(_builder, _network_socket, _network_dest_endpoint,
                              yield);
        // send packet
      }
    }
  }

  //##################
  // class attributes
  //##################

  AgentIdType _agentId;
  Resource _resourceType;

  boost::asio::io_service::strand _strand;
  boost::asio::ip::udp::socket _local_socket;
  boost::asio::ip::udp::socket _network_socket;
  boost::asio::ip::udp::endpoint _network_dest_endpoint;
  boost::asio::ip::udp::endpoint _local_dest_endpoint;
  boost::asio::high_resolution_timer _timer;
  // asio stuff

  capnp::byte _local_data[maxUDPsize]; //2^16 bytes (max UDP packet size is 65,507 bytes)
  capnp::byte _network_data[networkBufLen];
  // persistent arrays for storing incoming udp packets

  capnp::MallocMessageBuilder _builder;
  // builder for storing outgoing (repeated) packets

  std::shared_ptr<spdlog::logger> logger;
};

udp::endpoint make_endpoint(std::string ip, int portnum) {
  return udp::endpoint(boost::asio::ip::address::from_string(ip), portnum);
}

void generateDefaultConfiguration(const char *configFile){
      // generate a default configuration and write it to disk

      rapidjson::Document d;
      d.SetObject();
      auto &allocator = d.GetAllocator();
      // init JSON object

      d.AddMember("resource-type", "battery", allocator);
      d.AddMember("agent-id", 1000, allocator);
      d.AddMember("GA-ip", "127.0.0.1", allocator);
      d.AddMember("GA-port", 12345, allocator);
      d.AddMember("RA-ip", "127.0.0.1", allocator);
      d.AddMember("RA-port", 12342, allocator);
      d.AddMember("listenport-RA-side", 12340, allocator);
      d.AddMember("listenport-GA-side", 12341, allocator);
      // populate JSON object

      writeJSONfile(configFile, d);
      // write JSON object to disk
}

int commandLineParser(int argc, char *argv[], std::string& configFile, ResourceMap& resources) {
  // This function handles command line arguments:
  //   * no command line arguments
  //   * '--generate' option
  //   * '--list-resouces' option
  //   * config file as argument
  //   # malformed arguments (i.e., more than one cl argument)
  //
  //   possibly updates configFile pointer
  //
  //   returns:
  //     false - some error occurred, program should terminate
  //     true  - configFile contains valid filename

  using std::cout;
  using std::endl;

  if (argc == 2) {
    if (std::string(argv[1]) == "--generate") {
      if (exists(configFile)) {

        cout << "Attempting to create '" << configFile
             << "', but that file already exists. Please remove that one first."
             << endl;
        return -1;
      }
      cout << "Generating configuration file... (This file can "
              "be edited by hand)" << endl;

      generateDefaultConfiguration(configFile.c_str());

      cout << "Done." << endl;
      return -1;
    }
    else if (std::string(argv[1]) == "--list-resources") {
      cout << "Available resource types:" << endl;
      for(auto& res: resources)
        cout << res.first << endl;
      return -1;

    } else { // command line arg is not an option
      configFile = (argv[1]);
      if (std::string(configFile) == "-")
        // read config from std input
        return 1;
      if (!exists(configFile) || !is_regular_file(configFile)) {
        cout << "Configuration file '" << configFile << "' could not be found."
             << endl;
        return -1;
      }
      return 0;
    }
  } else {
    cout << "Usage: " << argv[0] << " [config file]" << endl << endl;
    cout << "Other options:" << endl;
    cout << argv[0] << " -                    (read configuration from standard input)" << endl;
    cout << argv[0] << " --generate           (generates a default configuration)" << endl;
    cout << argv[0] << " --list-resources     (lists available resources)" << endl;
    return -1;
  }
}

// main function
int main(int argc, char *argv[]) {

  ResourceMap resources({{"pv", Resource::pv},
                         {"battery", Resource::battery},
                         {"fuelcell", Resource::fuelcell},
                         {"custom", Resource::custom},
                         {"discrete-uniform", Resource::discreteUnif},
                         {"discrete", Resource::discrete}});

  boost::asio::io_service io_service;
  // needed for ASIO's eventloop

  auto configFile = std::string("daemon-cfg.json");
  auto status = commandLineParser(argc, argv, configFile, resources);
  // possibly updates 'configFile' filename

  rapidjson::Document cfg;
  switch (status) {
  case 0:
    cfg = readJSONfile(configFile.c_str());
    break;
  case 1:
    cfg = readJSONstdin();
    break;
  default:
    return status;
  }
  // read command line parameters

  if (!cfg.IsObject()) {
    std::cout << "Malformed JSON object in configuration file" << std::endl;
    return -1;
  }
  // read the configuration parameters from disk

  try {
    CommelecDaemon<> daemon(
        io_service, getInt(cfg, "agent-id"),
        resources.at(getString(cfg, "resource-type")),
        static_cast<PortNumberType>(getInt(cfg, "listenport-RA-side")),
        static_cast<PortNumberType>(getInt(cfg, "listenport-GA-side")),
        make_endpoint(getString(cfg, "RA-ip"),
                      static_cast<PortNumberType>(getInt(cfg, "RA-port"))),
        make_endpoint(getString(cfg, "GA-ip"),
                      static_cast<PortNumberType>(getInt(cfg, "GA-port"))));
    //instantiate our main class, with the parameters as set by the user in the config file

    io_service.run();
    // run asio's event-loop; used for asynchronous network IO using coroutines

  } catch (std::runtime_error e) {
    std::cout << "Config error: '" << e.what() << "' missing" << std::endl;
    return -1;
  } catch (std::out_of_range e) {
    std::cout << "Config error - unknown resource type: "
              << getString(cfg, "resource-type") << std::endl;
    return -1;
  }
}

<|endoftext|>


<commit_before>//
//  RenderObject.cpp
//  nativeGraphics
//
//  Created by Ling-Ling Zhang on 5/9/13.
//  Copyright (c) 2013 Ling-Ling Zhang. All rights reserved.
//

#include "RenderObject.h"
#include "glsl_helper.h"
#include "obj_parser.h"
#include "transform.h"
#include "common.h"
#include "log.h"

RenderObject::RenderObject(const char *objFilename, const char *vertexShaderFilename, const char *fragmentShaderFilename) {

    // Parse obj file into an interleaved float buffer
    GLfloat * interleavedBuffer = getInterleavedBuffer((char *)resourceCallback(objFilename), numVertices, true, true);
    glGenBuffers(1, &gVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices * (3+3+2) * sizeof(float), interleavedBuffer, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    checkGlError("VertexBuffer Generation");
    free(interleavedBuffer);

    // Compile and link shader program
    gProgram = createProgram((char *)resourceCallback(vertexShaderFilename), (char *)resourceCallback(fragmentShaderFilename));

    // Get uniform and attrib locations
    gmvMatrixHandle = glGetUniformLocation(gProgram, "u_MVMatrix");
    gmvpMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
    gvPositionHandle = glGetAttribLocation(gProgram, "a_Position");
    gvNormals = glGetAttribLocation(gProgram, "a_Normal");
    gvTexCoords = glGetAttribLocation(gProgram, "a_TexCoordinate");
    textureUniform = glGetUniformLocation(gProgram, "u_Texture");
    checkGlError("glGetAttribLocation");
}

void RenderObject::AddTexture(const char *textureFilename) {
    // Load textures
    GLubyte *imageData = (GLubyte *)resourceCallback(textureFilename); // TODO: Free this

    GLuint texName; // TODO
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); // TODO: hardcoded size

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    //glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);
    free(imageData);

    checkGlError("AddTexture");
    textures.push_back(texName);
}

void RenderObject::RenderFrame() {

    if(numVertices == 0) {
        LOGE("Setup not yet called.");
        return;
    }

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    // Matrices setup
    GLfloat* mv_Matrix = (GLfloat*)mvMatrix();
    GLfloat* mvp_Matrix = (GLfloat*)mvpMatrix();

    glUniformMatrix4fv(gmvMatrixHandle, 1, GL_FALSE, mv_Matrix);
    glUniformMatrix4fv(gmvpMatrixHandle, 1, GL_FALSE, mvp_Matrix);
    checkGlError("glUniformMatrix4fv");
    delete mv_Matrix;
    delete mvp_Matrix;

    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);

    // Vertices
    glEnableVertexAttribArray(gvPositionHandle);
    glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) 0);
    checkGlError("gvPositionHandle");

    // Normals
    glEnableVertexAttribArray(gvNormals);
    glVertexAttribPointer(gvNormals, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) (3 * sizeof(GLfloat)));
    checkGlError("gvNormals");

    //Textures
    glEnableVertexAttribArray(gvTexCoords);
    glVertexAttribPointer(gvTexCoords, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid *) (6 * sizeof(GLfloat)));
    checkGlError("gvTexCoords");

    if (textures.size() > 0) {

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glUniform1i(textureUniform, 0);
        checkGlError("texture");
    }

    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    checkGlError("glDrawArrays");

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
<commit_msg>Minor bug fix.<commit_after>//
//  RenderObject.cpp
//  nativeGraphics
//
//  Created by Ling-Ling Zhang on 5/9/13.
//  Copyright (c) 2013 Ling-Ling Zhang. All rights reserved.
//

#include "RenderObject.h"
#include "glsl_helper.h"
#include "obj_parser.h"
#include "transform.h"
#include "common.h"
#include "log.h"

RenderObject::RenderObject(const char *objFilename, const char *vertexShaderFilename, const char *fragmentShaderFilename) {

    // Parse obj file into an interleaved float buffer
    GLfloat * interleavedBuffer = getInterleavedBuffer((char *)resourceCallback(objFilename), numVertices, true, true);
    glGenBuffers(1, &gVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices * (3+3+2) * sizeof(float), interleavedBuffer, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    checkGlError("VertexBuffer Generation");
    free(interleavedBuffer);

    // Compile and link shader program
    gProgram = createProgram((char *)resourceCallback(vertexShaderFilename), (char *)resourceCallback(fragmentShaderFilename));

    // Get uniform and attrib locations
    gmvMatrixHandle = glGetUniformLocation(gProgram, "u_MVMatrix");
    gmvpMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
    gvPositionHandle = glGetAttribLocation(gProgram, "a_Position");
    gvNormals = glGetAttribLocation(gProgram, "a_Normal");
    gvTexCoords = glGetAttribLocation(gProgram, "a_TexCoordinate");
    textureUniform = glGetUniformLocation(gProgram, "u_Texture");
    checkGlError("glGetAttribLocation");
}

void RenderObject::AddTexture(const char *textureFilename) {
    // Load textures
    GLubyte *imageData = (GLubyte *)resourceCallback(textureFilename);

    GLuint texName; // TODO
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); // TODO: hardcoded size

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    //glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);
    free(imageData);

    checkGlError("AddTexture");
    textures.push_back(texName);
}

void RenderObject::RenderFrame() {

    if(numVertices == 0) {
        LOGE("Setup not yet called.");
        return;
    }

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    // Matrices setup
    GLfloat* mv_Matrix = (GLfloat*)mvMatrix();
    GLfloat* mvp_Matrix = (GLfloat*)mvpMatrix();

    glUniformMatrix4fv(gmvMatrixHandle, 1, GL_FALSE, mv_Matrix);
    glUniformMatrix4fv(gmvpMatrixHandle, 1, GL_FALSE, mvp_Matrix);
    checkGlError("glUniformMatrix4fv");
    delete mv_Matrix;
    delete mvp_Matrix;

    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);

    // Vertices
    glEnableVertexAttribArray(gvPositionHandle);
    glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) 0);
    checkGlError("gvPositionHandle");

    // Normals
    glEnableVertexAttribArray(gvNormals);
    glVertexAttribPointer(gvNormals, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) (3 * sizeof(GLfloat)));
    checkGlError("gvNormals");

    //Textures
    if(textures.size() > 0) {
    	glEnableVertexAttribArray(gvTexCoords);
    	glVertexAttribPointer(gvTexCoords, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid *) (6 * sizeof(GLfloat)));
    	checkGlError("gvTexCoords");

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glUniform1i(textureUniform, 0);
        checkGlError("texture");
    }

    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    checkGlError("glDrawArrays");

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Robert Escriva
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Replicant nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// STL
#include <algorithm>
#include <memory>

// Google Log
#include <glog/logging.h>

// Replicant
#include "common/configuration.h"

using replicant::chain_node;
using replicant::configuration;

configuration :: configuration()
    : m_cluster()
    , m_prev_token()
    , m_this_token()
    , m_version()
    , m_members()
    , m_chain()
    , m_command_sz()
{
}

configuration :: configuration(uint64_t c,
                               uint64_t pt,
                               uint64_t tt,
                               uint64_t v,
                               const chain_node& h)
    : m_cluster(c)
    , m_prev_token(pt)
    , m_this_token(tt)
    , m_version(v)
    , m_members()
    , m_chain()
    , m_command_sz()
{
    m_members.push_back(h);
    m_chain.push_back(h.token);
    m_command_sz = 1;
}

configuration :: ~configuration() throw ()
{
}

bool
configuration :: validate() const
{
    for (size_t i = 0; i < m_members.size(); ++i)
    {
        for (size_t j = i + 1; j < m_members.size(); ++j)
        {
            if (m_members[i].token == m_members[j].token ||
                m_members[i].address == m_members[j].address)
            {
                return false;
            }
        }
    }

    if (m_command_sz > m_chain.size())
    {
        return false;
    }

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        const chain_node* n = node_from_token(m_chain[i]);

        if (n == NULL)
        {
            return false;
        }

        for (size_t j = i + 1; j < m_chain.size(); ++j)
        {
            if (m_chain[i] == m_chain[j])
            {
                return false;
            }
        }
    }

    return true;
}

bool
configuration :: quorum_of(const configuration& other) const
{
    assert(validate());
    assert(other.validate());
    assert(cluster() == other.cluster());
    size_t count = 0;

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        for (size_t j = 0; j < other.m_chain.size(); ++j)
        {
            if (m_chain[i] == other.m_chain[j])
            {
                ++count;
                break;
            }
        }
    }

    size_t quorum = other.m_chain.size() / 2 + 1;
    return count >= quorum;
}

uint64_t
configuration :: fault_tolerance() const
{
    if (m_chain.empty())
    {
        return 0;
    }

    return (m_chain.size() - 1) / 2;
}

uint64_t
configuration :: servers_needed_for(uint64_t f) const
{
    uint64_t needed = f * 2 + 1;

    if (needed < m_chain.size())
    {
        return 0;
    }
    else
    {
        return needed - m_chain.size();
    }
}

bool
configuration :: has_token(uint64_t token) const
{
    return node_from_token(token) != NULL;
}

bool
configuration :: is_member(const chain_node& node) const
{
    const chain_node* n = node_from_token(node.token);
    return n && *n == node;
}

const chain_node*
configuration :: node_from_token(uint64_t token) const
{
    for (size_t i = 0; i < m_members.size(); ++i)
    {
        if (m_members[i].token == token)
        {
            return &m_members[i];
        }
    }

    return NULL;
}

const chain_node*
configuration :: head() const
{
    if (m_chain.empty())
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[0]);
    assert(n);
    return n;
}

const chain_node*
configuration :: command_tail() const
{
    assert(m_command_sz <= m_chain.size());

    if (m_command_sz == 0)
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[m_command_sz - 1]);
    assert(n);
    return n;
}

const chain_node*
configuration :: config_tail() const
{
    if (m_chain.empty())
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[m_chain.size() - 1]);
    assert(n);
    return n;
}

const chain_node*
configuration :: prev(uint64_t token) const
{
    const uint64_t* p = NULL;
    const uint64_t* cur = &m_chain.front();
    const uint64_t* end = &m_chain.front() + m_chain.size();

    for (; cur < end; ++cur)
    {
        if (*cur == token)
        {
            const chain_node* node = NULL;

            if (p)
            {
                node = node_from_token(*p);
                assert(node);
            }

            return node;
        }

        p = cur;
    }

    return NULL;
}

const chain_node*
configuration :: next(uint64_t token) const
{
    const uint64_t* n = NULL;
    const uint64_t* cur = &m_chain.front() + m_chain.size() - 1;
    const uint64_t* end = &m_chain.front();

    for (; cur >= end; --cur)
    {
        if (*cur == token)
        {
            const chain_node* node = NULL;

            if (n)
            {
                node = node_from_token(*n);
                assert(node);
            }

            return node;
        }

        n = cur;
    }

    return NULL;
}

bool
configuration :: in_command_chain(uint64_t token) const
{
    assert(m_command_sz <= m_chain.size());

    for (size_t i = 0; i < m_command_sz; ++i)
    {
        if (m_chain[i] == token)
        {
            return true;
        }
    }

    return false;
}

bool
configuration :: in_config_chain(uint64_t token) const
{
    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        if (m_chain[i] == token)
        {
            return true;
        }
    }

    return false;
}

uint64_t
configuration :: command_size() const
{
    return m_command_sz;
}

uint64_t
configuration :: config_size() const
{
    return m_chain.size();
}

const chain_node*
configuration :: members_begin() const
{
    return &m_members.front();
}

const chain_node*
configuration :: members_end() const
{
    return &m_members.front() + m_members.size();
}

const uint64_t*
configuration :: chain_begin() const
{
    return &m_chain.front();
}

const uint64_t*
configuration :: chain_end() const
{
    return &m_chain.front() + m_chain.size();
}

void
configuration :: bump_version()
{
    m_prev_token = m_this_token;
    // XXX m_this_token = token
    ++m_version;
}

void
configuration :: add_member(const chain_node& node)
{
    assert(node_from_token(node.token) == NULL);
    m_members.push_back(node);
    std::sort(m_members.begin(), m_members.end());
}

void
configuration :: add_to_chain(uint64_t token)
{
    assert(!in_config_chain(token));
    m_chain.push_back(token);
}

void
configuration :: remove_from_chain(uint64_t token)
{
    assert(in_config_chain(token));

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        if (m_chain[i] == token)
        {
            if (i < m_command_sz)
            {
                --m_command_sz;
            }

            for (size_t j = i; j + 1 < m_chain.size(); ++j)
            {
                m_chain[j] = m_chain[j + 1];
            }

            m_chain.pop_back();
            return;
        }
    }
}

void
configuration :: grow_command_chain()
{
    assert(m_command_sz < m_chain.size());
    ++m_command_sz;
}

bool
replicant :: operator < (const configuration& lhs, const configuration& rhs)
{
    return lhs.version() < rhs.version();
}

bool
replicant :: operator == (const configuration& lhs, const configuration& rhs)
{
    if (lhs.m_cluster != rhs.m_cluster ||
        lhs.m_prev_token != rhs.m_prev_token ||
        lhs.m_this_token != rhs.m_this_token ||
        lhs.m_version != rhs.m_version ||
        lhs.m_members.size() != rhs.m_members.size() ||
        lhs.m_chain.size() != rhs.m_chain.size() ||
        lhs.m_command_sz != rhs.m_command_sz)
    {
        return false;
    }

    for (size_t i = 0; i < lhs.m_members.size(); ++i)
    {
        if (lhs.m_members[i] != rhs.m_members[i])
        {
            return false;
        }
    }

    for (size_t i = 0; i < lhs.m_chain.size(); ++i)
    {
        if (lhs.m_chain[i] != rhs.m_chain[i])
        {
            return false;
        }
    }

    return true;
}

std::ostream&
replicant :: operator << (std::ostream& lhs, const configuration& rhs)
{
    lhs << "configuration(cluster=" << rhs.m_cluster
        << ", prev_token=" << rhs.m_prev_token
        << ", this_token=" << rhs.m_this_token
        << ", version=" << rhs.m_version
        << ", command=[";

    for (size_t i = 0; i < std::min(rhs.m_command_sz, rhs.m_chain.size()); ++i)
    {
        lhs << rhs.m_chain[i] << (i + 1 < std::min(rhs.m_command_sz, rhs.m_chain.size()) ? ", " : "");
    }

    lhs << "], config=[";

    for (size_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs << rhs.m_chain[i] << (i + 1 < rhs.m_chain.size() ? ", " : "");
    }

    lhs << "], members=[";

    for (size_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs << rhs.m_members[i] << (i + 1 < rhs.m_members.size() ? ", " : "");
    }

    lhs << "])";
    return lhs;
}

e::buffer::packer
replicant :: operator << (e::buffer::packer lhs, const configuration& rhs)
{
    lhs = lhs << rhs.m_cluster
              << rhs.m_prev_token
              << rhs.m_this_token
              << rhs.m_version
              << uint64_t(rhs.m_members.size())
              << rhs.m_command_sz
              << uint64_t(rhs.m_chain.size());

    for (uint64_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs = lhs << rhs.m_members[i];
    }

    for (uint64_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs = lhs << rhs.m_chain[i];
    }

    return lhs;
}

e::unpacker
replicant :: operator >> (e::unpacker lhs, configuration& rhs)
{
    uint64_t members_sz;
    uint64_t chain_sz;
    lhs = lhs >> rhs.m_cluster
              >> rhs.m_prev_token
              >> rhs.m_this_token
              >> rhs.m_version
              >> members_sz
              >> rhs.m_command_sz
              >> chain_sz;
    rhs.m_members.resize(members_sz);
    rhs.m_chain.resize(chain_sz);

    for (uint64_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs = lhs >> rhs.m_members[i];
    }

    for (uint64_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs = lhs >> rhs.m_chain[i];
    }

    return lhs;
}

char*
replicant :: pack_config(const configuration& config, char* ptr)
{
    // XXX inefficient, lazy hack
    std::auto_ptr<e::buffer> msg(e::buffer::create(pack_size(config)));
    msg->pack_at(0) << config;
    memmove(ptr, msg->data(), msg->size());
    return ptr + msg->size();
}

size_t
replicant :: pack_size(const configuration& rhs)
{
    size_t sz = sizeof(uint64_t) // rhs.m_cluster
              + sizeof(uint64_t) // rhs.m_prev_token
              + sizeof(uint64_t) // rhs.m_this_token
              + sizeof(uint64_t) // rhs.m_version
              + sizeof(uint64_t) // rhs.m_members.size()
              + sizeof(uint64_t) // rhs.m_command_sz
              + sizeof(uint64_t); // rhs.m_chain.size()

    for (size_t i = 0; i < rhs.m_members.size(); ++i)
    {
        sz += pack_size(rhs.m_members[i]);
    }

    sz += sizeof(uint64_t) * rhs.m_chain.size();
    return sz;
}

size_t
replicant :: pack_size(const std::vector<configuration>& rhs)
{
    size_t sz = sizeof(uint32_t);

    for (size_t i = 0; i < rhs.size(); ++i)
    {
        sz += pack_size(rhs[i]);
    }

    return sz;
}
<commit_msg>macosx build<commit_after>// Copyright (c) 2012, Robert Escriva
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Replicant nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// STL
#include <algorithm>
#include <memory>

// Google Log
#include <glog/logging.h>

// Replicant
#include "common/configuration.h"

using replicant::chain_node;
using replicant::configuration;

configuration :: configuration()
    : m_cluster()
    , m_prev_token()
    , m_this_token()
    , m_version()
    , m_members()
    , m_chain()
    , m_command_sz()
{
}

configuration :: configuration(uint64_t c,
                               uint64_t pt,
                               uint64_t tt,
                               uint64_t v,
                               const chain_node& h)
    : m_cluster(c)
    , m_prev_token(pt)
    , m_this_token(tt)
    , m_version(v)
    , m_members()
    , m_chain()
    , m_command_sz()
{
    m_members.push_back(h);
    m_chain.push_back(h.token);
    m_command_sz = 1;
}

configuration :: ~configuration() throw ()
{
}

bool
configuration :: validate() const
{
    for (size_t i = 0; i < m_members.size(); ++i)
    {
        for (size_t j = i + 1; j < m_members.size(); ++j)
        {
            if (m_members[i].token == m_members[j].token ||
                m_members[i].address == m_members[j].address)
            {
                return false;
            }
        }
    }

    if (m_command_sz > m_chain.size())
    {
        return false;
    }

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        const chain_node* n = node_from_token(m_chain[i]);

        if (n == NULL)
        {
            return false;
        }

        for (size_t j = i + 1; j < m_chain.size(); ++j)
        {
            if (m_chain[i] == m_chain[j])
            {
                return false;
            }
        }
    }

    return true;
}

bool
configuration :: quorum_of(const configuration& other) const
{
    assert(validate());
    assert(other.validate());
    assert(cluster() == other.cluster());
    size_t count = 0;

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        for (size_t j = 0; j < other.m_chain.size(); ++j)
        {
            if (m_chain[i] == other.m_chain[j])
            {
                ++count;
                break;
            }
        }
    }

    size_t quorum = other.m_chain.size() / 2 + 1;
    return count >= quorum;
}

uint64_t
configuration :: fault_tolerance() const
{
    if (m_chain.empty())
    {
        return 0;
    }

    return (m_chain.size() - 1) / 2;
}

uint64_t
configuration :: servers_needed_for(uint64_t f) const
{
    uint64_t needed = f * 2 + 1;

    if (needed < m_chain.size())
    {
        return 0;
    }
    else
    {
        return needed - m_chain.size();
    }
}

bool
configuration :: has_token(uint64_t token) const
{
    return node_from_token(token) != NULL;
}

bool
configuration :: is_member(const chain_node& node) const
{
    const chain_node* n = node_from_token(node.token);
    return n && *n == node;
}

const chain_node*
configuration :: node_from_token(uint64_t token) const
{
    for (size_t i = 0; i < m_members.size(); ++i)
    {
        if (m_members[i].token == token)
        {
            return &m_members[i];
        }
    }

    return NULL;
}

const chain_node*
configuration :: head() const
{
    if (m_chain.empty())
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[0]);
    assert(n);
    return n;
}

const chain_node*
configuration :: command_tail() const
{
    assert(m_command_sz <= m_chain.size());

    if (m_command_sz == 0)
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[m_command_sz - 1]);
    assert(n);
    return n;
}

const chain_node*
configuration :: config_tail() const
{
    if (m_chain.empty())
    {
        return NULL;
    }

    const chain_node* n = node_from_token(m_chain[m_chain.size() - 1]);
    assert(n);
    return n;
}

const chain_node*
configuration :: prev(uint64_t token) const
{
    const uint64_t* p = NULL;
    const uint64_t* cur = &m_chain.front();
    const uint64_t* end = &m_chain.front() + m_chain.size();

    for (; cur < end; ++cur)
    {
        if (*cur == token)
        {
            const chain_node* node = NULL;

            if (p)
            {
                node = node_from_token(*p);
                assert(node);
            }

            return node;
        }

        p = cur;
    }

    return NULL;
}

const chain_node*
configuration :: next(uint64_t token) const
{
    const uint64_t* n = NULL;
    const uint64_t* cur = &m_chain.front() + m_chain.size() - 1;
    const uint64_t* end = &m_chain.front();

    for (; cur >= end; --cur)
    {
        if (*cur == token)
        {
            const chain_node* node = NULL;

            if (n)
            {
                node = node_from_token(*n);
                assert(node);
            }

            return node;
        }

        n = cur;
    }

    return NULL;
}

bool
configuration :: in_command_chain(uint64_t token) const
{
    assert(m_command_sz <= m_chain.size());

    for (size_t i = 0; i < m_command_sz; ++i)
    {
        if (m_chain[i] == token)
        {
            return true;
        }
    }

    return false;
}

bool
configuration :: in_config_chain(uint64_t token) const
{
    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        if (m_chain[i] == token)
        {
            return true;
        }
    }

    return false;
}

uint64_t
configuration :: command_size() const
{
    return m_command_sz;
}

uint64_t
configuration :: config_size() const
{
    return m_chain.size();
}

const chain_node*
configuration :: members_begin() const
{
    return &m_members.front();
}

const chain_node*
configuration :: members_end() const
{
    return &m_members.front() + m_members.size();
}

const uint64_t*
configuration :: chain_begin() const
{
    return &m_chain.front();
}

const uint64_t*
configuration :: chain_end() const
{
    return &m_chain.front() + m_chain.size();
}

void
configuration :: bump_version()
{
    m_prev_token = m_this_token;
    // XXX m_this_token = token
    ++m_version;
}

void
configuration :: add_member(const chain_node& node)
{
    assert(node_from_token(node.token) == NULL);
    m_members.push_back(node);
    std::sort(m_members.begin(), m_members.end());
}

void
configuration :: add_to_chain(uint64_t token)
{
    assert(!in_config_chain(token));
    m_chain.push_back(token);
}

void
configuration :: remove_from_chain(uint64_t token)
{
    assert(in_config_chain(token));

    for (size_t i = 0; i < m_chain.size(); ++i)
    {
        if (m_chain[i] == token)
        {
            if (i < m_command_sz)
            {
                --m_command_sz;
            }

            for (size_t j = i; j + 1 < m_chain.size(); ++j)
            {
                m_chain[j] = m_chain[j + 1];
            }

            m_chain.pop_back();
            return;
        }
    }
}

void
configuration :: grow_command_chain()
{
    assert(m_command_sz < m_chain.size());
    ++m_command_sz;
}

bool
replicant :: operator < (const configuration& lhs, const configuration& rhs)
{
    return lhs.version() < rhs.version();
}

bool
replicant :: operator == (const configuration& lhs, const configuration& rhs)
{
    if (lhs.m_cluster != rhs.m_cluster ||
        lhs.m_prev_token != rhs.m_prev_token ||
        lhs.m_this_token != rhs.m_this_token ||
        lhs.m_version != rhs.m_version ||
        lhs.m_members.size() != rhs.m_members.size() ||
        lhs.m_chain.size() != rhs.m_chain.size() ||
        lhs.m_command_sz != rhs.m_command_sz)
    {
        return false;
    }

    for (size_t i = 0; i < lhs.m_members.size(); ++i)
    {
        if (lhs.m_members[i] != rhs.m_members[i])
        {
            return false;
        }
    }

    for (size_t i = 0; i < lhs.m_chain.size(); ++i)
    {
        if (lhs.m_chain[i] != rhs.m_chain[i])
        {
            return false;
        }
    }

    return true;
}

std::ostream&
replicant :: operator << (std::ostream& lhs, const configuration& rhs)
{
    lhs << "configuration(cluster=" << rhs.m_cluster
        << ", prev_token=" << rhs.m_prev_token
        << ", this_token=" << rhs.m_this_token
        << ", version=" << rhs.m_version
        << ", command=[";

    for (size_t i = 0; i < std::min((size_t)rhs.m_command_sz, rhs.m_chain.size()); ++i)
    {
        lhs << rhs.m_chain[i] << (i + 1 < std::min((size_t)rhs.m_command_sz, rhs.m_chain.size()) ? ", " : "");
    }

    lhs << "], config=[";

    for (size_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs << rhs.m_chain[i] << (i + 1 < rhs.m_chain.size() ? ", " : "");
    }

    lhs << "], members=[";

    for (size_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs << rhs.m_members[i] << (i + 1 < rhs.m_members.size() ? ", " : "");
    }

    lhs << "])";
    return lhs;
}

e::buffer::packer
replicant :: operator << (e::buffer::packer lhs, const configuration& rhs)
{
    lhs = lhs << rhs.m_cluster
              << rhs.m_prev_token
              << rhs.m_this_token
              << rhs.m_version
              << uint64_t(rhs.m_members.size())
              << rhs.m_command_sz
              << uint64_t(rhs.m_chain.size());

    for (uint64_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs = lhs << rhs.m_members[i];
    }

    for (uint64_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs = lhs << rhs.m_chain[i];
    }

    return lhs;
}

e::unpacker
replicant :: operator >> (e::unpacker lhs, configuration& rhs)
{
    uint64_t members_sz;
    uint64_t chain_sz;
    lhs = lhs >> rhs.m_cluster
              >> rhs.m_prev_token
              >> rhs.m_this_token
              >> rhs.m_version
              >> members_sz
              >> rhs.m_command_sz
              >> chain_sz;
    rhs.m_members.resize(members_sz);
    rhs.m_chain.resize(chain_sz);

    for (uint64_t i = 0; i < rhs.m_members.size(); ++i)
    {
        lhs = lhs >> rhs.m_members[i];
    }

    for (uint64_t i = 0; i < rhs.m_chain.size(); ++i)
    {
        lhs = lhs >> rhs.m_chain[i];
    }

    return lhs;
}

char*
replicant :: pack_config(const configuration& config, char* ptr)
{
    // XXX inefficient, lazy hack
    std::auto_ptr<e::buffer> msg(e::buffer::create(pack_size(config)));
    msg->pack_at(0) << config;
    memmove(ptr, msg->data(), msg->size());
    return ptr + msg->size();
}

size_t
replicant :: pack_size(const configuration& rhs)
{
    size_t sz = sizeof(uint64_t) // rhs.m_cluster
              + sizeof(uint64_t) // rhs.m_prev_token
              + sizeof(uint64_t) // rhs.m_this_token
              + sizeof(uint64_t) // rhs.m_version
              + sizeof(uint64_t) // rhs.m_members.size()
              + sizeof(uint64_t) // rhs.m_command_sz
              + sizeof(uint64_t); // rhs.m_chain.size()

    for (size_t i = 0; i < rhs.m_members.size(); ++i)
    {
        sz += pack_size(rhs.m_members[i]);
    }

    sz += sizeof(uint64_t) * rhs.m_chain.size();
    return sz;
}

size_t
replicant :: pack_size(const std::vector<configuration>& rhs)
{
    size_t sz = sizeof(uint32_t);

    for (size_t i = 0; i < rhs.size(); ++i)
    {
        sz += pack_size(rhs[i]);
    }

    return sz;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#include "sort.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <set>
#include <sstream>
#include <string>
#include <vector>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/noncopyable.hpp>
#include <boost/ptr_container/ptr_unordered_map.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/variant/recursive_variant.hpp>

#include "db/driver.hh"
#include "db/query.h"
#include "db/statement-driver.hh"
#include "lexer.hh"

using std::cerr;
using std::endl;
using std::set;
using std::string;
using std::vector;

using namespace boost::spirit;

namespace compiler {
namespace sort {

struct Compound;

typedef boost::variant<boost::recursive_wrapper<Compound>,
					   std::string,
					   int,
					   flint::lexer::Real
					   > Expr;

struct Compound {
	std::vector<Expr> children;
};

struct Entry {
	std::string uuid;
	std::string name;
	Expr expr;
};

}
}

BOOST_FUSION_ADAPT_STRUCT(compiler::sort::Compound,
						  (std::vector<compiler::sort::Expr>, children))

BOOST_FUSION_ADAPT_STRUCT(compiler::sort::Entry,
						  (std::string, uuid)
						  (std::string, name)
						  (compiler::sort::Expr, expr))

namespace compiler {
namespace sort {
namespace {

class DependencyCollector : public boost::static_visitor<> {
public:
	DependencyCollector(const string &name,
						const set<string> &candidates,
						set<string> *dependencies)
		: name_(name)
		, candidates_(candidates)
		, dependencies_(dependencies)
	{}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator it, end = c.children.end();
		for (it=c.children.begin();it!=end;++it) {
			boost::apply_visitor(*this, *it);
		}
	}

	void operator()(const std::string &s) const {
		if (s != name_ && candidates_.count(s) > 0) {
			dependencies_->insert(s);
		}
	}

	void operator()(int /*i*/) const {
		// nothing to do
	}

	void operator()(const flint::lexer::Real &) const {
		// nothing to do
	}

private:
	const string &name_;
	const set<string> &candidates_;
	set<string> *dependencies_;
};

class Printer : public boost::static_visitor<> {
public:
	explicit Printer(std::ostream *os)
		: os_(os)
	{
	}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator bit = c.children.begin();
		std::vector<Expr>::const_iterator eit = c.children.end();
		os_->put('(');
		for (std::vector<Expr>::const_iterator it=bit;it!=eit;++it) {
			if (it != bit) os_->put(' ');
			boost::apply_visitor(*this, *it);
		}
		os_->put(')');
	}

	void operator()(const std::string &s) const {
		*os_ << s;
	}

	void operator()(int i) const {
		*os_ << i;
	}

	void operator()(const flint::lexer::Real &r) const {
		*os_ << r.lexeme;
	}

private:
	std::ostream *os_;
};

template<typename TLexer>
struct Lexer : lex::lexer<TLexer> {

	Lexer() {
		this->self.add_pattern
			("DIGIT", "[0-9]")
			("SIGN", "[-+]")
			("EXPONENT", "[eE]{SIGN}?{DIGIT}+")
			("FLOAT", "{SIGN}?({DIGIT}*\".\"{DIGIT}+{EXPONENT}?|{DIGIT}+{EXPONENT})")
			;

		uuid36 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
		real = "{FLOAT}";
		integer = "{SIGN}?{DIGIT}+";
		id = "[%@][a-zA-Z_][a-zA-Z_0-9:#]*";
		keyword = "[$]?[a-zA-Z_][a-zA-Z_0-9]*";

		this->self = lex::token_def<>('\n') | '\r' | '(' | ')' | ' ';
		this->self += uuid36 | real | integer | id | keyword;
	}

	lex::token_def<std::string> uuid36, id, keyword;
	lex::token_def<int> integer;
	lex::token_def<flint::lexer::Real> real;
};

template<typename TIterator>
struct Grammar : qi::grammar<TIterator, Expr()> {

	template<typename TTokenDef>
	Grammar(TTokenDef const &td)
	: Grammar::base_type(expr)
	{
		expr %= (compound | td.real | td.integer | td.id | td.keyword);

		compound %= '(' >> (expr % ' ') >> ')';
	}

	qi::rule<TIterator, Expr()> expr;
	qi::rule<TIterator, Compound()> compound;
};

class Line : boost::noncopyable {
public:
	Line(const std::string &name, const Expr &expr)
		: name_(name),
		  expr_(expr)
	{
	}

	const string &name() const {return name_;}

	size_t CollectDependencies(const std::set<string> &candidates, set<string> *dependencies) {
		boost::apply_visitor(DependencyCollector(name_, candidates, dependencies), expr_);
		return dependencies->size();
	}

	std::string GetMath() const {
		std::ostringstream oss;
		boost::apply_visitor(Printer(&oss), expr_);
		return oss.str();
	}

private:
	std::string name_;
	Expr expr_;
};

class LineVector : boost::noncopyable {
public:
	size_t GetSize() const {
		return lines_.size();
	}

	void Add(Line *line) {
		lines_.push_back(line);
	}

	bool CalculateLevels(int *levels) {
		size_t n = lines_.size();
		set<string> names;
		for (size_t i=0;i<n;i++) {
			names.insert(lines_[i].name());
			levels[i] = -1;
		}
		set<string> solved;
		boost::scoped_array<set<string> > dependencies(new set<string>[n]);
		for (size_t i=0;i<n;i++) {
			Line &line = lines_[i];
			if (line.CollectDependencies(names, dependencies.get()+i) == 0) {
				solved.insert(line.name());
				levels[i] = 0;
			}
		}
		if (solved.empty()) {
			// we have nothing to do if there is no level 0
			return true;
		}
		int level = 1;
		while (!std::includes(solved.begin(), solved.end(),
							  names.begin(), names.end())) {
			bool found = false;
			for (size_t i=0;i<n;i++) {
				if (levels[i] < 0) {
					const Line &line = lines_[i];
					if (std::includes(solved.begin(), solved.end(),
									  dependencies[i].begin(), dependencies[i].end())) {
						solved.insert(line.name());
						levels[i] = level;
						found = true;
					}
				}
			}
			if (!found) {
				set<string> unsolved;
				std::set_difference(names.begin(), names.end(),
									solved.begin(), solved.end(),
									std::inserter(unsolved, unsolved.end()));
				cerr << "failed to calculate level:";
				for (set<string>::const_iterator it=unsolved.begin();it!=unsolved.end();++it) {
					cerr << " " << *it;
				}
				cerr << endl;
				return false;
			}
			level++;
		}
		return true;
	}

	const Line &at(size_t m) const {
		return lines_.at(m);
	}

private:
	boost::ptr_vector<Line> lines_;
};

class IndexAndLevel {
public:
	IndexAndLevel(size_t index, int level) : index_(index), level_(level) {}

	size_t index() const {return index_;}

	bool operator<(const IndexAndLevel &other) const {
		return level_ < other.level_;
	}

private:
	size_t index_;
	int level_;
};

typedef boost::ptr_unordered_map<string, LineVector> UuidMap;

/*
 * This class creates and keeps both tokens and grammar objects which
 * construction is expensive in terms of performance.
 */
class Parser {
public:
	typedef const char *base_iterator_type;
	typedef lex::lexertl::token<base_iterator_type> token_type;
	typedef lex::lexertl::lexer<token_type> lexer_type;
	typedef Lexer<lexer_type> RealLexer;
	typedef Grammar<RealLexer::iterator_type> RealGrammar;

	explicit Parser(UuidMap *um)
		: tokens_()
		, grammar_(tokens_)
		, um_(um)
	{
	}

	int Parse(const char *uuid, const char *name, const char *math) {
		base_iterator_type it = math;
		base_iterator_type eit = math + std::strlen(math);
		Expr expr;
		bool r = lex::tokenize_and_parse(it, eit, tokens_, grammar_, expr);
		if (!r || it != eit) {
			cerr << "failed to parse: " << *it << endl;
			return 1;
		}
		(*um_)[uuid].Add(new Line(name, expr));
		return 0;
	}

private:
	RealLexer tokens_;
	RealGrammar grammar_;
	UuidMap *um_;
};

int Process(void *data, int argc, char **argv, char **names)
{
	(void)names;
	assert(argc == 3);
	Parser *parser = static_cast<Parser *>(data);
	return parser->Parse(argv[0], argv[1], argv[2]);
}

class Inserter : db::StatementDriver {
public:
	explicit Inserter(sqlite3 *db)
		: db::StatementDriver(db, "INSERT INTO sorts VALUES (?, ?, ?)")
	{
	}

	bool Insert(const char *uuid, const char *name, const char *math) {
		int e;
		e = sqlite3_bind_text(stmt(), 1, uuid, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind uuid: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 2, name, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind name: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 3, math, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind math: " << e << endl;
			return false;
		}
		e = sqlite3_step(stmt());
		if (e != SQLITE_DONE) {
			cerr << "failed to step: " << e << endl;
			return false;
		}
		sqlite3_reset(stmt());
		return true;
	}
};

}

bool Sort(sqlite3 *db)
{
	UuidMap um;
	{
		Parser parser(&um);
		char *em;
		int e;
		e = sqlite3_exec(db, "SELECT * FROM asts", Process, &parser, &em);
		if (e != SQLITE_OK) {
			cerr << "failed to exec: " << e
				 << ": " << em << endl;
			sqlite3_free(em);
			return false;
		}
	}

	if (!BeginTransaction(db))
		return false;
	if (!CreateTable(db, "sorts", "(uuid TEXT, name TEXT, math TEXT)"))
		return false;

	Inserter inserter(db);
	for (UuidMap::iterator umit=um.begin();umit!=um.end();++umit) {
		size_t n = umit->second->GetSize();
		boost::scoped_array<int> arr(new int[n]);
		if (!umit->second->CalculateLevels(arr.get())) {
			return false;
		}
		vector<IndexAndLevel> v;
		for (size_t k=0;k<n;k++) {
			v.push_back(IndexAndLevel(k, arr[k]));
		}
		std::stable_sort(v.begin(), v.end());
		for (vector<IndexAndLevel>::const_iterator vit=v.begin();vit!=v.end();++vit) {
			size_t m = vit->index();
			const Line &line(umit->second->at(m));
			std::string math = line.GetMath();
			if (!inserter.Insert(umit->first.c_str(),
								 line.name().c_str(),
								 math.c_str()))
				return false;
		}
	}
	return CommitTransaction(db);
}

}
}
<commit_msg>more efficient way to achieve the same result<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#include "sort.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/noncopyable.hpp>
#include <boost/ptr_container/ptr_unordered_map.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/variant/recursive_variant.hpp>

#include "db/driver.hh"
#include "db/query.h"
#include "db/statement-driver.hh"
#include "lexer.hh"

using std::cerr;
using std::endl;
using std::string;
using std::vector;

using namespace boost::spirit;

namespace compiler {
namespace sort {

struct Compound;

typedef boost::variant<boost::recursive_wrapper<Compound>,
					   std::string,
					   int,
					   flint::lexer::Real
					   > Expr;

struct Compound {
	std::vector<Expr> children;
};

struct Entry {
	std::string uuid;
	std::string name;
	Expr expr;
};

}
}

BOOST_FUSION_ADAPT_STRUCT(compiler::sort::Compound,
						  (std::vector<compiler::sort::Expr>, children))

BOOST_FUSION_ADAPT_STRUCT(compiler::sort::Entry,
						  (std::string, uuid)
						  (std::string, name)
						  (compiler::sort::Expr, expr))

namespace compiler {
namespace sort {
namespace {

class DependencyCollector : public boost::static_visitor<> {
public:
	DependencyCollector(const string &name,
						const std::unordered_map<string, size_t> &candidates,
						std::unordered_set<size_t> *dependencies)
		: name_(name)
		, candidates_(candidates)
		, dependencies_(dependencies)
	{}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator it, end = c.children.end();
		for (it=c.children.begin();it!=end;++it) {
			boost::apply_visitor(*this, *it);
		}
	}

	void operator()(const std::string &s) const {
		if (s == name_)
			return;
		std::unordered_map<string, size_t>::const_iterator it = candidates_.find(s);
		if (it != candidates_.cend())
			dependencies_->insert(it->second);
	}

	void operator()(int /*i*/) const {
		// nothing to do
	}

	void operator()(const flint::lexer::Real &) const {
		// nothing to do
	}

private:
	const string &name_;
	const std::unordered_map<string, size_t> &candidates_;
	std::unordered_set<size_t> *dependencies_;
};

class Printer : public boost::static_visitor<> {
public:
	explicit Printer(std::ostream *os)
		: os_(os)
	{
	}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator bit = c.children.begin();
		std::vector<Expr>::const_iterator eit = c.children.end();
		os_->put('(');
		for (std::vector<Expr>::const_iterator it=bit;it!=eit;++it) {
			if (it != bit) os_->put(' ');
			boost::apply_visitor(*this, *it);
		}
		os_->put(')');
	}

	void operator()(const std::string &s) const {
		*os_ << s;
	}

	void operator()(int i) const {
		*os_ << i;
	}

	void operator()(const flint::lexer::Real &r) const {
		*os_ << r.lexeme;
	}

private:
	std::ostream *os_;
};

template<typename TLexer>
struct Lexer : lex::lexer<TLexer> {

	Lexer() {
		this->self.add_pattern
			("DIGIT", "[0-9]")
			("SIGN", "[-+]")
			("EXPONENT", "[eE]{SIGN}?{DIGIT}+")
			("FLOAT", "{SIGN}?({DIGIT}*\".\"{DIGIT}+{EXPONENT}?|{DIGIT}+{EXPONENT})")
			;

		uuid36 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
		real = "{FLOAT}";
		integer = "{SIGN}?{DIGIT}+";
		id = "[%@][a-zA-Z_][a-zA-Z_0-9:#]*";
		keyword = "[$]?[a-zA-Z_][a-zA-Z_0-9]*";

		this->self = lex::token_def<>('\n') | '\r' | '(' | ')' | ' ';
		this->self += uuid36 | real | integer | id | keyword;
	}

	lex::token_def<std::string> uuid36, id, keyword;
	lex::token_def<int> integer;
	lex::token_def<flint::lexer::Real> real;
};

template<typename TIterator>
struct Grammar : qi::grammar<TIterator, Expr()> {

	template<typename TTokenDef>
	Grammar(TTokenDef const &td)
	: Grammar::base_type(expr)
	{
		expr %= (compound | td.real | td.integer | td.id | td.keyword);

		compound %= '(' >> (expr % ' ') >> ')';
	}

	qi::rule<TIterator, Expr()> expr;
	qi::rule<TIterator, Compound()> compound;
};

class Line : boost::noncopyable {
public:
	Line(const std::string &name, const Expr &expr)
		: name_(name),
		  expr_(expr)
	{
	}

	const string &name() const {return name_;}

	size_t CollectDependencies(const std::unordered_map<string, size_t> &candidates, std::unordered_set<size_t> *dependencies) {
		boost::apply_visitor(DependencyCollector(name_, candidates, dependencies), expr_);
		return dependencies->size();
	}

	std::string GetMath() const {
		std::ostringstream oss;
		boost::apply_visitor(Printer(&oss), expr_);
		return oss.str();
	}

private:
	std::string name_;
	Expr expr_;
};

class LineVector : boost::noncopyable {
public:
	size_t GetSize() const {
		return lines_.size();
	}

	void Add(Line *line) {
		lines_.push_back(line);
	}

	bool CalculateLevels(int *levels) {
		size_t n = lines_.size();
		std::unordered_map<string, size_t> nm;
		for (size_t i=0;i<n;i++) {
			auto p = nm.insert(std::make_pair(lines_[i].name(), i));
			if (!p.second) {
				cerr << "more than one entries for " << p.first->first << endl;
				return false;
			}
			levels[i] = -1;
		}
		std::unique_ptr<std::unordered_set<size_t>[]> dependencies(new std::unordered_set<size_t>[n]);
		size_t total = 0;
		for (size_t i=0;i<n;i++) {
			Line &line = lines_[i];
			if (line.CollectDependencies(nm, dependencies.get()+i) == 0) {
				levels[i] = 0;
				total++;
			}
		}
		if (total == 0) {
			// we have nothing to do if there is no level 0
			return true;
		}
		int level = 1;
		while (total < n) {
			bool found = false;
			for (size_t i=0;i<n;i++) {
				if (levels[i] >= 0) continue;
				if (std::all_of(dependencies[i].begin(), dependencies[i].end(),
								[&levels](size_t k){return 0 <= levels[k];})) {
					levels[i] = level;
					total++;
					found = true;
				}
			}
			if (!found) {
				cerr << "failed to calculate level:";
				for (size_t i=0;i<n;i++) {
					if (levels[i] < 0)
						cerr << " " << lines_[i].name();
				}
				cerr << endl;
				return false;
			}
			level++;
		}
		return true;
	}

	const Line &at(size_t m) const {
		return lines_.at(m);
	}

private:
	boost::ptr_vector<Line> lines_;
};

class IndexAndLevel {
public:
	IndexAndLevel(size_t index, int level) : index_(index), level_(level) {}

	size_t index() const {return index_;}

	bool operator<(const IndexAndLevel &other) const {
		return level_ < other.level_;
	}

private:
	size_t index_;
	int level_;
};

typedef boost::ptr_unordered_map<string, LineVector> UuidMap;

/*
 * This class creates and keeps both tokens and grammar objects which
 * construction is expensive in terms of performance.
 */
class Parser {
public:
	typedef const char *base_iterator_type;
	typedef lex::lexertl::token<base_iterator_type> token_type;
	typedef lex::lexertl::lexer<token_type> lexer_type;
	typedef Lexer<lexer_type> RealLexer;
	typedef Grammar<RealLexer::iterator_type> RealGrammar;

	explicit Parser(UuidMap *um)
		: tokens_()
		, grammar_(tokens_)
		, um_(um)
	{
	}

	int Parse(const char *uuid, const char *name, const char *math) {
		base_iterator_type it = math;
		base_iterator_type eit = math + std::strlen(math);
		Expr expr;
		bool r = lex::tokenize_and_parse(it, eit, tokens_, grammar_, expr);
		if (!r || it != eit) {
			cerr << "failed to parse: " << *it << endl;
			return 1;
		}
		(*um_)[uuid].Add(new Line(name, expr));
		return 0;
	}

private:
	RealLexer tokens_;
	RealGrammar grammar_;
	UuidMap *um_;
};

int Process(void *data, int argc, char **argv, char **names)
{
	(void)names;
	assert(argc == 3);
	Parser *parser = static_cast<Parser *>(data);
	return parser->Parse(argv[0], argv[1], argv[2]);
}

class Inserter : db::StatementDriver {
public:
	explicit Inserter(sqlite3 *db)
		: db::StatementDriver(db, "INSERT INTO sorts VALUES (?, ?, ?)")
	{
	}

	bool Insert(const char *uuid, const char *name, const char *math) {
		int e;
		e = sqlite3_bind_text(stmt(), 1, uuid, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind uuid: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 2, name, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind name: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 3, math, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind math: " << e << endl;
			return false;
		}
		e = sqlite3_step(stmt());
		if (e != SQLITE_DONE) {
			cerr << "failed to step: " << e << endl;
			return false;
		}
		sqlite3_reset(stmt());
		return true;
	}
};

}

bool Sort(sqlite3 *db)
{
	UuidMap um;
	{
		Parser parser(&um);
		char *em;
		int e;
		e = sqlite3_exec(db, "SELECT * FROM asts", Process, &parser, &em);
		if (e != SQLITE_OK) {
			cerr << "failed to exec: " << e
				 << ": " << em << endl;
			sqlite3_free(em);
			return false;
		}
	}

	if (!BeginTransaction(db))
		return false;
	if (!CreateTable(db, "sorts", "(uuid TEXT, name TEXT, math TEXT)"))
		return false;

	Inserter inserter(db);
	for (UuidMap::iterator umit=um.begin();umit!=um.end();++umit) {
		size_t n = umit->second->GetSize();
		boost::scoped_array<int> arr(new int[n]);
		if (!umit->second->CalculateLevels(arr.get())) {
			return false;
		}
		vector<IndexAndLevel> v;
		for (size_t k=0;k<n;k++) {
			v.push_back(IndexAndLevel(k, arr[k]));
		}
		std::stable_sort(v.begin(), v.end());
		for (vector<IndexAndLevel>::const_iterator vit=v.begin();vit!=v.end();++vit) {
			size_t m = vit->index();
			const Line &line(umit->second->at(m));
			std::string math = line.GetMath();
			if (!inserter.Insert(umit->first.c_str(),
								 line.name().c_str(),
								 math.c_str()))
				return false;
		}
	}
	return CommitTransaction(db);
}

}
}
<|endoftext|>


<commit_before>//Fitting a TGraph2D
//Author: Olivier Couet

#include <TMath.h>
#include <TGraph2D.h>
#include <TRandom.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TF2.h>
#include <TH1.h>

TCanvas* graph2dfit()
{
   gStyle->SetOptStat(0);
   gStyle->SetOptFit();

   TCanvas *c = new TCanvas("c","Graph2D example",0,0,800,800);
   c->Divide(2,3);

   Double_t rnd, x, y, z;
   Double_t e = 0.3;
   Int_t nd = 400;
   Int_t np = 10000;

   TRandom r;
   Double_t fl = 6;
   TF2  *f2 = new TF2("f2","1000*(([0]*sin(x)/x)*([1]*sin(y)/y))+200",
      -fl,fl,-fl,fl);
   f2->SetParameters(1,1);
   TGraph2D *dt = new TGraph2D();

   // Fill the 2D graph
   Double_t zmax = 0;
   for (Int_t N=0; N<nd; N++) {
      f2->GetRandom2(x,y);
      // Generate a random number in [-e,e]
      rnd = 2*r.Rndm()*e-e;
      z = f2->Eval(x,y)*(1+rnd);
      if (z>zmax) zmax = z;
      dt->SetPoint(N,x,y,z);
   }

   Double_t hr = 350;
   TH1D *h1 = new TH1D("h1", "#splitline{Difference between Original function}\
   {and Function with noise}", 100, -hr, hr);
   TH1D *h2 = new TH1D("h2",
      "#splitline{Difference between Original function}\
      {and Interpolation with Delaunay triangles}", 100, -hr, hr);
   TH1D *h3 = new TH1D("h3", "#splitline{Difference between Original function}\
   {and Minuit fit}", 500, -hr, hr);

   f2->SetParameters(0.5,1.5);
   dt->Fit(f2);
   TF2 *fit2 = (TF2*)dt->FindObject("f2");

   f2->SetParameters(1,1);

   for (Int_t N=0; N<np; N++) {
      f2->GetRandom2(x,y);
      // Generate a random number in [-e,e]
      rnd = 2*r.Rndm()*e-e;
      z = f2->Eval(x,y)*(1+rnd);
      h1->Fill(f2->Eval(x,y)-z);
      z = dt->Interpolate(x,y);
      h2->Fill(f2->Eval(x,y)-z);
      z = fit2->Eval(x,y);
      h3->Fill(f2->Eval(x,y)-z);
   }

   gStyle->SetPalette(1);
   c->cd(1);
   f2->SetTitle("Original function with Graph2D points on top");
   f2->SetMaximum(zmax);
   gStyle->SetHistTopMargin(0);
   f2->Draw("surf1");
   dt->Draw("same p0");

   c->cd(3);
   dt->SetMargin(0.1);
   dt->SetFillColor(36);
   dt->SetTitle("Histogram produced with Delaunay interpolation");
   dt->Draw("surf4");

   c->cd(5);
   fit2->SetTitle("Minuit fit result on the Graph2D points");
   fit2->Draw("surf1");

   h1->SetFillColor(47);
   h2->SetFillColor(38);
   h3->SetFillColor(29);

   c->cd(2); h1->Fit("gaus","Q") ; h1->Draw();
   c->cd(4); h2->Fit("gaus","Q") ; h2->Draw();
   c->cd(6); h3->Fit("gaus","Q") ; h3->Draw();
   c->cd();
   return c;
}
<commit_msg>- The last mod was wrong: one should not put a "\"    between the two parts of "#splitline".<commit_after>//Fitting a TGraph2D
//Author: Olivier Couet

#include <TMath.h>
#include <TGraph2D.h>
#include <TRandom.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TF2.h>
#include <TH1.h>

TCanvas* graph2dfit()
{
   gStyle->SetOptStat(0);
   gStyle->SetOptFit();

   TCanvas *c = new TCanvas("c","Graph2D example",0,0,800,800);
   c->Divide(2,3);

   Double_t rnd, x, y, z;
   Double_t e = 0.3;
   Int_t nd = 400;
   Int_t np = 10000;

   TRandom r;
   Double_t fl = 6;
   TF2  *f2 = new TF2("f2","1000*(([0]*sin(x)/x)*([1]*sin(y)/y))+200",
      -fl,fl,-fl,fl);
   f2->SetParameters(1,1);
   TGraph2D *dt = new TGraph2D();

   // Fill the 2D graph
   Double_t zmax = 0;
   for (Int_t N=0; N<nd; N++) {
      f2->GetRandom2(x,y);
      // Generate a random number in [-e,e]
      rnd = 2*r.Rndm()*e-e;
      z = f2->Eval(x,y)*(1+rnd);
      if (z>zmax) zmax = z;
      dt->SetPoint(N,x,y,z);
   }

   Double_t hr = 350;
   TH1D *h1 = new TH1D("h1",
   "#splitline{Difference between Original function}{and Function with noise}",
   100, -hr, hr);
   TH1D *h2 = new TH1D("h2",
   "#splitline{Difference between Original function}{and Interpolation with Delaunay triangles}",
   100, -hr, hr);
   TH1D *h3 = new TH1D("h3",
   "#splitline{Difference between Original function}{and Minuit fit}",
   500, -hr, hr);

   f2->SetParameters(0.5,1.5);
   dt->Fit(f2);
   TF2 *fit2 = (TF2*)dt->FindObject("f2");

   f2->SetParameters(1,1);

   for (Int_t N=0; N<np; N++) {
      f2->GetRandom2(x,y);
      // Generate a random number in [-e,e]
      rnd = 2*r.Rndm()*e-e;
      z = f2->Eval(x,y)*(1+rnd);
      h1->Fill(f2->Eval(x,y)-z);
      z = dt->Interpolate(x,y);
      h2->Fill(f2->Eval(x,y)-z);
      z = fit2->Eval(x,y);
      h3->Fill(f2->Eval(x,y)-z);
   }

   gStyle->SetPalette(1);
   c->cd(1);
   f2->SetTitle("Original function with Graph2D points on top");
   f2->SetMaximum(zmax);
   gStyle->SetHistTopMargin(0);
   f2->Draw("surf1");
   dt->Draw("same p0");

   c->cd(3);
   dt->SetMargin(0.1);
   dt->SetFillColor(36);
   dt->SetTitle("Histogram produced with Delaunay interpolation");
   dt->Draw("surf4");

   c->cd(5);
   fit2->SetTitle("Minuit fit result on the Graph2D points");
   fit2->Draw("surf1");

   h1->SetFillColor(47);
   h2->SetFillColor(38);
   h3->SetFillColor(29);

   c->cd(2); h1->Fit("gaus","Q") ; h1->Draw();
   c->cd(4); h2->Fit("gaus","Q") ; h2->Draw();
   c->cd(6); h3->Fit("gaus","Q") ; h3->Draw();
   c->cd();
   return c;
}
<|endoftext|>