text:
// TRENTO: Reduced Thickness Event-by-event Nuclear Topology
// Copyright 2015-2020 Jonah E. Bernhard, J. Scott Moreland, Derek Soeder
// MIT License

#include <string>
#include <stdexcept>
#include <vector>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/tokenizer.hpp>

#include "eventbin.h"
#include "eventqty.h"

namespace trento {

namespace {

static void validate_edges(const std::vector<double>& edges) {
  if (edges.size() < 2)
    throw std::invalid_argument{"cannot bin with fewer than two edges"};

  auto it = std::begin(edges);
  double prev = *it;
  double edge = *(++it);
  if (prev == edge)
    throw std::invalid_argument{"bin edges cannot be equal"};
  bool ascending = (prev < edge);

  while (++it != std::end(edges)) {
    prev = edge;
    edge = *it;
    if (prev == edge)
      throw std::invalid_argument{"bin edges cannot be equal"};
    else if ((prev < edge) != ascending)
      throw std::invalid_argument{"bin edges must be monotonic"};
  }
}

static size_t binary_search_ascending_for_discard(const std::vector<size_t>& permwithflag, const std::vector<double>& values, double target) {
  size_t i = 0;
  for (size_t j = permwithflag.size(); i < j; ) {  // keep `j` past the end of the search range to avoid computing `(j - 1)`, which could underflow
    auto k = (i + j - 1) / 2;
    auto value = values[permwithflag[k] >> 1];  // LSB is deletion flag
    if (target > value)
      i = k + 1;
    else if (target < value)
      j = k;
    else return k;
  }

  return i;
}

static void remove_for_discard(const std::vector<size_t>& permwithflag, std::vector<double>& values) {
  size_t n = permwithflag.size();

  size_t i;
  for (i = 0; i < n; ++i)
    if (permwithflag[i] & 1) break;  // LSB is deletion flag

  size_t j = i;
  for ( ; i < n; ++i)
    if (!(permwithflag[i] & 1))
      values[j++] = values[i];

  values.resize(j);
}

static int binary_search_bins_ascending(const std::vector<double>& edges, double target) {
  size_t i = 0;
  for (size_t j = edges.size() - 1; (i + 1) < j; ) {  // ensures `i <= edges.size() - 2`
    auto k = (i + j) / 2;
    auto edge = edges[k];
    if (target < edge)  // smaller (left) edge is inclusive, larger (right) edge is exclusive
      j = k;
    else i = k;
  }

  return ((target >= edges[i] && target < edges[i + 1]) ? static_cast<int>(i) : -1);
}

static int binary_search_bins_descending(const std::vector<double>& edges, double target) {
  size_t i = 0;
  for (size_t j = edges.size() - 1; (i + 1) < j; ) {  // ensures `i <= edges.size() - 2`
    auto k = (i + j) / 2;
    auto edge = edges[k];
    if (target >= edge)  // smaller (right) edge is inclusive, larger (left) edge is exclusive
      j = k;
    else i = k;
  }

  return ((target < edges[i] && target >= edges[i + 1]) ? static_cast<int>(i) : -1);
}

}  // unnamed namespace

EventBinner::EventBinner(const std::vector<EventQuantity>& event_columns)
  : event_columns_(event_columns),
    num_all_columns_(event_columns_.size())
{
  for (auto qty : event_columns_)
    data_[qty];  // creates entry if it does not exist
}

void EventBinner::set_subsample(size_t count) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  subsample_ = count;
}

void EventBinner::add_axis(EventQuantity qty, std::vector<double>&& edges) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  validate_edges(edges);

  data_[qty];  // creates entry if it does not exist

  // BinAxis::{quantity, edges, ascending, is_percentile} (via constructor)
  axes_.emplace_back( qty, std::forward<std::vector<double>>(edges), (edges.front() < edges.back()), false );
}

void EventBinner::add_axis_percentile(EventQuantity qty, std::vector<double>&& edges) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  validate_edges(edges);

  data_[qty];  // creates entry if it does not exist

  // BinAxis::{quantity, edges, ascending, is_percentile} (via constructor)
  axes_.emplace_back( qty, std::forward<std::vector<double>>(edges), (edges.front() < edges.back()), true );
  delay_binning_ = true;
}

void EventBinner::add_axis_percentile(EventQuantity qty, std::vector<double>&& edges, double include_value, bool in_last_bin) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  validate_edges(edges);

  data_[qty];  // creates entry if it does not exist

  // BinAxis::{quantity, edges, ascending, first_inclusion, last_inclusion} (via constructor)
  axes_.emplace_back( qty, std::forward<std::vector<double>>(edges), (edges.front() < edges.back()), include_value, in_last_bin );
  delay_binning_ = true;
}

void EventBinner::add_axis_percentile(EventQuantity qty, std::vector<double>&& edges, double include_first, double include_last) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  validate_edges(edges);

  data_[qty];  // creates entry if it does not exist

  // BinAxis::{quantity, edges, ascending, first_inclusion, last_inclusion} (via constructor)
  axes_.emplace_back( qty, std::move(edges), (edges.front() < edges.back()), include_first, include_last );
  delay_binning_ = true;
}

void EventBinner::add_discard(EventQuantity qty, bool greater_than, double value) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  data_[qty];  // creates entry if it does not exist

  // DiscardCriterion::{quantity, greater_than, value, is_percentile} (via constructor)
  discard_criteria_.emplace_back( qty, greater_than, value, false );
}

void EventBinner::add_discard_percentile(EventQuantity qty, bool greater_than, double percentile) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  data_[qty];  // creates entry if it does not exist

  // DiscardCriterion::{quantity, greater_than, value, is_percentile} (via constructor)
  discard_criteria_.emplace_back( qty, greater_than, percentile, true );
  delay_binning_ = true;
}

void EventBinner::add_power_columns(const std::vector<std::pair<EventQuantity, double>>& power_columns) {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot reconfigure binner once processing has started"};

  for (const auto& column : power_columns)
    data_[column.first];  // creates entry if it does not exist

  power_columns_.insert(std::end(power_columns_), std::begin(power_columns), std::end(power_columns));
  num_all_columns_ += power_columns.size();
}

void EventBinner::start() {
  if (state_ != BinnerConfiguring)
    throw std::logic_error{"cannot call start() twice"};

  if (axes_.size() == 0)
    throw std::invalid_argument{"no bin edges were supplied"};

  size_t limit = ((std::numeric_limits<size_t>::max() / 2) / sizeof(decltype(bin_sums_)::value_type)) / std::max(num_all_columns_, static_cast<size_t>(1));
  size_t numbins = 1;

  for (const auto& axis : axes_) {
    auto axisbins = (axis.edges.size() - 1);

    if (axisbins > limit)
      throw std::invalid_argument{"too many bins"};

    numbins *= axisbins;
    limit   /= axisbins;
  }

  bin_counts_.resize(numbins);
  bin_sums_.resize(numbins * num_all_columns_);

  state_ = BinnerProcessing;
}

void EventBinner::process(const Event& event) {
  if (state_ != BinnerProcessing)
    throw std::logic_error{"call start() before processing events"};

  ++numevents_;

  if (delay_binning_) {
    for (auto& field : data_)
      field.second.push_back(event.get<double>(field.first));

    if (++numevents_pending_ == subsample_ && subsample_ != 0)
      resolve_percentiles();  // clears `delay_binning_`
  }
  else if (!should_discard(event)) {
    std::function<double(EventQuantity)> fn = std::bind(&Event::get<double>, &event, std::placeholders::_1);
    bin_event(fn);
  }
}

void EventBinner::finish() {
  if (state_ != BinnerProcessing)
    throw std::logic_error{"finish() can only be called during event processing"};

  if (delay_binning_) {
    subsample_ = 0;
    resolve_percentiles();
  }

  state_ = BinnerFinished;
}

EventBinner::bin_iterator EventBinner::begin() const {
  if (state_ != BinnerFinished)
    throw std::logic_error{"call finish() before accessing bins"};

  return bin_iterator(*this, 0);
}

EventBinner::bin_iterator EventBinner::end() const {
  if (state_ != BinnerFinished)
    throw std::logic_error{"call finish() before accessing bins"};

  return bin_iterator(*this, bin_counts_.size());
}

bool EventBinner::should_discard(const Event& event) const {
  // all percentiles should have been resolved by this point, so 'cut.is_percentile' should always be false
  for (const auto& cut : discard_criteria_) {
    double value = event.get<double>(cut.quantity);
    if (cut.greater_than ? (value >= cut.value) : (value <= cut.value))  // always discard if value is exactly at cutoff
      return true;
  }

  return false;
}

void EventBinner::bin_event(std::function<double(EventQuantity)> getter) {
  size_t index = 0;
  for (const auto& axis : axes_) {
    index *= (axis.edges.size() - 1);

    auto value = getter(axis.quantity);
    int b = (axis.ascending ? binary_search_bins_ascending : binary_search_bins_descending)(axis.edges, value);
    if (b < 0) return;

    index += static_cast<size_t>(b);
  }

  bin_counts_[index]++;

  index *= num_all_columns_;

  for (auto qty : event_columns_) {
    auto value = getter(qty);
    std::pair<double, double>& sums = bin_sums_[index++];
    sums.first  += value;
    sums.second += (value * value);
  }

  for (const auto& qtypower : power_columns_) {
    auto value = std::pow(getter(qtypower.first), qtypower.second);
    std::pair<double, double>& sums = bin_sums_[index++];
    sums.first  += value;
    sums.second += (value * value);
  }
}

void EventBinner::resolve_percentiles() {
  if (!delay_binning_)
    throw std::logic_error{"no unresolved percentiles"};

  std::vector<size_t> perm;
  size_t nevents = numevents_pending_;

  // apply discard cuts

  if (!discard_criteria_.empty()) {
    std::sort(
      std::begin(discard_criteria_), std::end(discard_criteria_),
      [](const DiscardCriterion& a, const DiscardCriterion& b) { return (a.quantity < b.quantity); } );

    EventQuantity lastqty = EventQuantity_None;

    // `perm` is a sort permutation and also maintains a deletion flag for each element
    perm.resize(nevents);  // `resize` and assign actually seems to be faster than `reserve` and `emplace_back`
    for (size_t i = 0; i < nevents; ++i)
      perm[i] = (i << 1);  // LSB is deletion flag; compute `(perm[...] >> 1)` to convert to an index

    for (auto& cut : discard_criteria_) {
      auto qty = cut.quantity;
      const auto& values = data_[qty];

      if (qty != lastqty) {
        std::sort( std::begin(perm), std::end(perm), [&values](size_t a, size_t b) { return values[a >> 1] < values[b >> 1]; } );  // always sorts ascending
        lastqty = qty;
      }

      size_t start;
      if (cut.is_percentile) {
        start = static_cast<size_t>(std::round(perm.size() * cut.value));

        cut.value = values[((start < perm.size()) ? perm[start] : perm.back()) >> 1];  // doesn't account for manual inclusions or first/last edges, but cuts shouldn't be that close to the ends anyway
        cut.is_percentile = false;
      }
      else {
        start = binary_search_ascending_for_discard(perm, values, cut.value);

        if (!(cut.greater_than) && start < perm.size() && values[perm[start] >> 1] == cut.value)
          ++start;  // exact matches are always discarded, for both `<` and `>`
      }

      if (cut.greater_than) {
        for (auto it = std::begin(perm) + static_cast<std::ptrdiff_t>(start); it != std::end(perm); ++it)
          *it |= 1;  // set deletion flag for this event
      }
      else {
        for (auto it = std::begin(perm), itend = it + static_cast<std::ptrdiff_t>(start); it != itend; ++it)
          *it |= 1;  // set deletion flag for this event
      }
    }

    std::sort(perm.begin(), perm.end());  // numerically sort `perm` to order deletion flags by the order in which events were recorded

    for (auto& field : data_) {
      remove_for_discard(perm, field.second);
      nevents = field.second.size();  // easy way to count how many events were kept; should be the same for all `field`s
    }

    perm.resize(0);  // empty `perm` so it can be reused (without reallocation) below
  }

  // resolve percentile bin edges

  for (auto& axis : axes_) {
    if (!axis.is_percentile)
      continue;

    axis.is_percentile = false;

    if (nevents == 0) {
      for (auto& edge : axis.edges)
        edge = 0.;
      continue;
    }

    // now `perm` is just a sort permutation (LSB is not special)
    if (perm.size() == 0) {
      perm.resize(nevents);  // `resize` and assign actually seems to be faster than `reserve` and `emplace_back`
      for (size_t i = 0; i < nevents; ++i)
        perm[i] = i;
    }

    const auto& values = data_[axis.quantity];

    std::sort( std::begin(perm), std::end(perm), [&values](size_t a, size_t b) { return values[a] < values[b]; } );

    for (auto& edge : axis.edges)
      edge = values[perm[std::min(static_cast<size_t>(std::round(nevents * edge)), nevents - 1)]];

    static constexpr double SMALL = 1E-6;

    if (axis.has_first_inclusion) {
      if (axis.ascending)
        axis.edges.front() = std::min(axis.edges.front(), axis.first_inclusion);
      else axis.edges.front() = std::max(axis.edges.front(), axis.first_inclusion);
    }
    else if (!axis.ascending) {
      if (std::abs(axis.edges.front()) < SMALL)
        axis.edges.front() = SMALL;
      else axis.edges.front() += (std::abs(axis.edges.front()) * SMALL);
    }

    if (axis.has_last_inclusion) {
      if (axis.ascending)
        axis.edges.back() = std::max(axis.edges.back(), axis.last_inclusion);
      else axis.edges.back() = std::min(axis.edges.back(), axis.last_inclusion);
    }
    else if (axis.ascending) {
      if (std::abs(axis.edges.back()) < SMALL)
        axis.edges.back() = SMALL;
      else axis.edges.back() += (std::abs(axis.edges.back()) * SMALL);
    }
  }

  // bin all pending events into the finalized bins

  for (size_t i = 0; i < nevents; ++i) {
    bin_event( [this, i](EventQuantity qty) -> double { return data_[qty][i]; } );
  }

  data_.clear();
  numevents_pending_ = 0;
  delay_binning_ = false;
}

//
// EventBinnerHelper class
//

std::pair<double, bool> EventBinnerHelper::parse_cutoff(const std::string& str) {
  double d;

  if (!boost::ends_with(str, "%")) {
    d = std::stod(str);
    if (std::isnan(d))
      throw std::invalid_argument{"quantity value must be a real number"};

    return std::make_pair(d, false);
  }

  if (boost::ends_with(str, "_%"))
    d = std::stod(str.substr(0, str.size() - 2));
  else d = 100. - std::stod(str.substr(0, str.size() - 1));

  if (d < 0. || d > 100. || !std::isfinite(d))
    throw std::invalid_argument{"percentile must be a real number from 0 to 100"};

  return std::make_pair(d / 100., true);
}

void EventBinnerHelper::parse_edges(const std::string& paramstr) {
  boost::char_separator<char> sep(",", "", boost::keep_empty_tokens);
  boost::tokenizer<boost::char_separator<char>> tokens(paramstr, sep);

  auto it = std::begin(tokens);
  if (it == std::end(tokens))
    throw std::invalid_argument{"bin edge list must begin with a quantity label"};

  auto qty = EventQuantityList::lookup(*it);

  std::vector<double> edges;
  bool pct = false;

  double inclusion1 = 0., inclusion2 = 0.;
  bool has_inclusion1 = false, has_inclusion2 = false;

  while (++it != std::end(tokens)) {
    auto edge = parse_cutoff(*it);

    if (edge.second) {  // is a percentile
      if (!pct && edges.size() == 1) {
        inclusion1 = edges.back();
        has_inclusion1 = true;
        edges.pop_back();
      }
      else if ((!pct && edges.size() != 0) || has_inclusion2)
        throw std::invalid_argument{"bin edges cannot be a mixture of values and percentiles"};

      edges.push_back(edge.first);
      pct = true;
    }
    else {  // not a percentile
      if (pct) {
        if (!has_inclusion2) {
          inclusion2 = edge.first;
          has_inclusion2 = true;
        }
        else throw std::invalid_argument{"bin edges cannot be a mixture of values and percentiles"};
      }
      else edges.push_back(edge.first);
    }
  }

  if (!pct) {
    binner_.add_axis(qty, std::move(edges));
  }
  else if (has_inclusion1) {
    if (has_inclusion2)
      binner_.add_axis_percentile(qty, std::move(edges), inclusion1, inclusion2);
    else binner_.add_axis_percentile(qty, std::move(edges), inclusion1, false);
  }
  else if (has_inclusion2)
    binner_.add_axis_percentile(qty, std::move(edges), inclusion2, true);
  else binner_.add_axis_percentile(qty, std::move(edges));

  require_quantity_callback_(qty);
}

void EventBinnerHelper::parse_discard(const std::string& inequality) {
  boost::char_separator<char> sep("", "<>", boost::keep_empty_tokens);
  boost::tokenizer<boost::char_separator<char>> tokens(inequality, sep);

  std::vector<std::string> tokenlist(std::begin(tokens), std::end(tokens));
  if (tokenlist.size() != 3 || (tokenlist[1] != "<" && tokenlist[1] != ">"))
    throw std::invalid_argument{"discard directive requires a strict inequality"};

  EventQuantity qty = EventQuantityList::lookup(tokenlist.front());
  bool gt = (tokenlist[1] == ">");
  auto&& cutoff = parse_cutoff(tokenlist.back());

  if (cutoff.second)
    binner_.add_discard_percentile(qty, gt, cutoff.first);
  else binner_.add_discard(qty, gt, cutoff.first);

  require_quantity_callback_(qty);
}

void EventBinnerHelper::parse_powercolumns(const std::string& columnsstr) {
  std::vector<std::pair<EventQuantity, double>> power_columns;

  boost::char_separator<char> sep(",", "", boost::keep_empty_tokens);
  boost::tokenizer<boost::char_separator<char>> tokens(columnsstr, sep);

  for (const auto& token : tokens) {
    auto x = token.find('^');
    auto qty = EventQuantityList::lookup(token.substr(0, x));
    double power = (x == std::string::npos) ? 1. : std::stod(token.substr(x + 1));

    power_columns.emplace_back(qty, power);

    require_quantity_callback_(qty);
  }

  binner_.add_power_columns(power_columns);
}

void EventBinnerHelper::parse_directives(const std::string& directives) {
  boost::char_separator<char> sep(":", "", boost::keep_empty_tokens);
  boost::tokenizer<boost::char_separator<char>> tokens(directives, sep);

  for (auto it = ++std::begin(tokens); it != std::end(tokens); ++it) {
    const auto& token = *it;
    auto x = token.find('=');
    std::string what = token.substr(0, x);

    if (what == "edges") {
      if (x == std::string::npos)
        throw std::invalid_argument{"edges directive requires a list"};

      parse_edges(token.substr(x + 1));
    }
    else if (what == "subsample") {
      if (x == std::string::npos)
        throw std::invalid_argument{"subsample directive requires a nonnegative integer"};

      binner_.set_subsample(std::stoul(token.substr(x + 1)));
    }
    else if (what == "discard") {
      if (x == std::string::npos)
        throw std::invalid_argument{"discard directive requires an inequality"};

      parse_discard(token.substr(x + 1));
    }
    else if (what == "powercolumns") {
      if (x == std::string::npos)
        throw std::invalid_argument{"powercolumns directive requires a list"};

      parse_powercolumns(token.substr(x + 1));
    }
    else {
      unhandled_directive_callback_(token);
    }
  }
}

void EventBinnerHelper::configure(EventBinner& binner, const std::string& directives,
  std::function<void(const std::string&)> unhandled_directive_callback,
  std::function<void(EventQuantity)> require_quantity_callback)
{
  EventBinnerHelper helper(binner, unhandled_directive_callback, require_quantity_callback);

  helper.parse_directives(directives);

  binner.start();
}

}  // namespace trento

ext: cxx

max_stars_repo_name: dereksoeder/trento

max_issues_repo_name: dereksoeder/trento

max_forks_repo_name: dereksoeder/trento


text:
/*
 *    Copyright (C) 2014 MongoDB Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the GNU Affero General Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#include "mongo/platform/basic.h"

#include "mongo/client/sasl_scramsha1_client_conversation.h"

#include <boost/algorithm/string/replace.hpp>

#include "mongo/base/parse_number.h"
#include "mongo/client/sasl_client_session.h"
#include "mongo/platform/random.h"
#include "mongo/util/base64.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/password_digest.h"
#include "mongo/util/text.h"

namespace mongo {
    SaslSCRAMSHA1ClientConversation::SaslSCRAMSHA1ClientConversation(
                                                    SaslClientSession* saslClientSession) :
        SaslClientConversation(saslClientSession),
        _step(0),
        _authMessage(""),
        _clientNonce("") {
    }

    SaslSCRAMSHA1ClientConversation::~SaslSCRAMSHA1ClientConversation(){
        // clear the _saltedPassword memory
        memset(_saltedPassword, 0, scram::hashSize);
    }

    StatusWith<bool> SaslSCRAMSHA1ClientConversation::step(const StringData& inputData,
                                                           std::string* outputData) {
        std::vector<std::string> input = StringSplitter::split(inputData.toString(), ",");
        _step++;

        switch (_step) {
            case 1:
                return _firstStep(outputData);
            case 2:
                // Append server-first-message to _authMessage
                _authMessage += inputData.toString() + ",";
                return _secondStep(input, outputData);
            case 3:
                return _thirdStep(input, outputData);
            default:
                return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                        mongoutils::str::stream() <<
                                        "Invalid SCRAM-SHA-1 authentication step: " << _step);
        }
    }

    /*
     * RFC 5802 specifies that in SCRAM user names characters ',' and '=' are encoded as
     * =2C and =3D respectively.
     */
    static void encodeSCRAMUsername(std::string& user) {
        boost::replace_all(user, "=", "=3D");
        boost::replace_all(user, ",", "=2C");
    }

    /*
     * Generate client-first-message of the form:
     * n,a=authzid,n=encoded-username,r=client-nonce
     */
    StatusWith<bool> SaslSCRAMSHA1ClientConversation::_firstStep(std::string* outputData) {

        // Create text-based nonce as base64 encoding of a binary blob of length multiple of 3
        const int nonceLenQWords = 3;
        uint64_t binaryNonce[nonceLenQWords];

        scoped_ptr<SecureRandom> sr(SecureRandom::create());

        binaryNonce[0] = sr->nextInt64();
        binaryNonce[1] = sr->nextInt64();
        binaryNonce[2] = sr->nextInt64();

        std::string user =
            _saslClientSession->getParameter(SaslClientSession::parameterUser).toString();
        encodeSCRAMUsername(user);
        std::string clientNonce = base64::encode(reinterpret_cast<char*>(binaryNonce),
                                                 sizeof(binaryNonce));

        // Append client-first-message-bare to authMessage
        _authMessage = "n=" + user + ",r=" + clientNonce + ",";

        StringBuilder sb;
        sb << "n,,n=" << user <<
              ",r=" << clientNonce;
        *outputData = sb.str();

        return StatusWith<bool>(false);

    }

    /**
     * Parse server-first-message on the form:
     * r=client-nonce|server-nonce,s=user-salt,i=iteration-count
     *
     * Generate client-final-message of the form:
     * c=channel-binding(base64),r=client-nonce|server-nonce,p=ClientProof
     *
     **/
    StatusWith<bool> SaslSCRAMSHA1ClientConversation::_secondStep(const std::vector<string>& input,
                                                                  std::string* outputData) {
        if (input.size() != 3) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect number of arguments for first SCRAM-SHA-1 server message, got " <<
                input.size() << " expected 3");
        }
        else if (!str::startsWith(input[0], "r=") || input[0].size() < 2) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect SCRAM-SHA-1 client|server nonce: " << input[0]);
        }
        else if (!str::startsWith(input[1], "s=") || input[1].size() < 6) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect SCRAM-SHA-1 salt: " << input[1]);
        }
        else if(!str::startsWith(input[2], "i=") || input[2].size() < 3) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect SCRAM-SHA-1 iteration count: " << input[2]);
        }

        std::string nonce = input[0].substr(2);
        if(!str::startsWith(nonce, _clientNonce)) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Server SCRAM-SHA-1 nonce does not match client nonce" << input[2]);
        }

        std::string salt = input[1].substr(2);
        int iterationCount;

        Status status = parseNumberFromStringWithBase(input[2].substr(2), 10, &iterationCount);
        if (status != Status::OK()) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Failed to parse SCRAM-SHA-1 iteration count: " << input[2]);
        }

        // Append client-final-message-without-proof to _authMessage
        _authMessage += "c=biws,r=" + nonce;

        std::string decodedSalt;
        try {
            decodedSalt = base64::decode(salt);
        }
        catch (const DBException& ex) {
            return StatusWith<bool>(ex.toStatus());
        }

        scram::generateSaltedPassword(
                            _saslClientSession->getParameter(SaslClientSession::parameterPassword),
                            reinterpret_cast<const unsigned char*>(decodedSalt.c_str()),
                            decodedSalt.size(),
                            iterationCount,
                            _saltedPassword);

        std::string clientProof = scram::generateClientProof(_saltedPassword, _authMessage);

        StringBuilder sb;
        sb << "c=biws,r=" << nonce << ",p=" << clientProof;
        *outputData = sb.str();

        return StatusWith<bool>(false);
    }

    /**
     * Verify server-final-message on the form:
     * v=ServerSignature
     *
     * or failed authentication server-final-message on the form:
     * e=message
     **/
    StatusWith<bool> SaslSCRAMSHA1ClientConversation::_thirdStep(const std::vector<string>& input,
                                                                  std::string* outputData) {

        if (input.size() != 1) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect number of arguments for final SCRAM-SHA-1 server message, got " <<
                input.size() << " expected 1");
        }
        else if (input[0].size() < 3) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect SCRAM-SHA-1 server message length: " << input[0]);
        }
        else if (str::startsWith(input[0], "e=")) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed, mongoutils::str::stream() <<
                "SCRAM-SHA-1 authentication failure: " << input[0].substr(2));
        }
        else if (!str::startsWith(input[0], "v=")) {
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                "Incorrect SCRAM-SHA-1 ServerSignature: " << input[0]);
        }

        bool validServerSignature =
            scram::verifyServerSignature(_saltedPassword, _authMessage, input[0].substr(2));

        if (!validServerSignature) {
            *outputData = "e=Invalid server signature";
            return StatusWith<bool>(ErrorCodes::BadValue, mongoutils::str::stream() <<
                    "Client failed to verify SCRAM-SHA-1 ServerSignature, received " <<
                    input[0].substr(2));
        }

        *outputData = "";

        return StatusWith<bool>(true);
    }
}  // namespace mongo

ext: cpp

max_stars_repo_name: joprice/mongo

max_issues_repo_name: wujf/mongo

max_forks_repo_name: wujf/mongo


text:
#ifndef INCLUDED_scheme_nest_maps_Rotation1DMap_HH
#define INCLUDED_scheme_nest_maps_Rotation1DMap_HH

#include "scheme/util/SimpleArray.hh"

#include <Eigen/Dense>

#include <boost/static_assert.hpp>
#include <iostream>
#include <vector>

namespace scheme { namespace nest { namespace pmap {

	template<
		int DIM=1,
		class Value=Eigen::Matrix3d,
		class Index=uint64_t,
		class Float=double
	>
	struct Rotation1DMap {
		BOOST_STATIC_ASSERT_MSG(DIM==1,"Rotation1D DIM must be == 1");

		static int const DIMENSION = DIM;
		typedef Value ValueType ;
		typedef Float FloatType ;
		typedef Index IndexType ;
		typedef util::SimpleArray<DIM,Index> Indices;
		typedef util::SimpleArray<DIM,Float> Params;
		typedef Eigen::Matrix<Float,3,1> V;
		typedef Eigen::Matrix<Float,3,3> M;

		Index nside;
		Float lb, ub;
		V axis, flipaxis;
		M flip;

		Rotation1DMap() : nside(1), lb(-M_PI), ub(M_PI), axis(0,0,1), flipaxis(0,0,0) {}
		Rotation1DMap( Params p, Params q, Indices i ) : lb(p[0]), ub(q[0]), nside(i[0]), axis(0,0,1), flipaxis(0,0,0) {}

		void set_axis(V a){ axis = a.normalized(); }

		void set_flip_axis(V a){
			BOOST_ASSERT( fabs(axis.dot(a)) < 0.00001 );
			a.normalize();
			flipaxis = a;
			flip = Eigen::AngleAxis<Float>(M_PI,a).toRotationMatrix();
		}

		///@brief sets value to parameters without change
		///@return false iff invalid parameters
		bool params_to_value(
			Params const & params,
			Index cell_index,
			Index resl,
			Value & value
		) const {
			BOOST_ASSERT( fabs(axis.norm()-1.0) < 0.00001 );
			BOOST_ASSERT( lb < ub );
			bool doflip = cell_index >= nside;
			cell_index -= doflip ? nside : 0;
			BOOST_ASSERT( cell_index < nside );
			Float ang = (Float)cell_index + params[0];
			ang *= (ub-lb) / (Float)nside;
			ang += lb;
			value = Eigen::AngleAxis<Float>( ang, axis ).matrix();
			value = value * ( doflip? flip : M::Identity() );
			BOOST_ASSERT( lb <= ang && ang <= ub );
			// std::cout << "SET " << doflip <<  std::endl;//axis.transpose() << " " << ang*180/M_PI << std::endl;
			// std::cout << value << std::endl;
			return true;
		}

		void get_axis_angle_and_flip( Value value, Eigen::Vector3d & ax, Float & ang, bool & doflip ) const {
			Eigen::AngleAxis<Float> aa(value);
			ang = aa.angle();
			ax = aa.axis();
			if( ax.dot(axis) < 0 ){ ax = -ax; ang = -ang; }
			doflip = false;
			if( fabs(ang) > 0.00001 && ax.dot(axis) < 0.999 ){
				doflip = true;
				value = value * flip.transpose();
				Eigen::AngleAxis<Float> aa(value);
				ax = aa.axis();
				ang = aa.angle();
				if( ax.dot(axis) < 0 ){ ax = -ax; ang = -ang; }
				// std::cout << ax.transpose() << " / " << axis.transpose() << " / " << ang*180/M_PI << std::endl;
				// std::cout << value << std::endl;
			}

		}

		///@brief sets params/cell_index from value
		///@note necessary for value lookup and neighbor lookup
		bool value_to_params(
			Value const & value0,
			Index /*resl*/,
			Params & params,
			Index & cell_index
		) const {
			M value = value0;
			BOOST_ASSERT( fabs(axis.norm()-1.0) < 0.00001 );
			BOOST_ASSERT( lb < ub );

			Float ang;
			bool doflip;
			Eigen::Vector3d vax;
			get_axis_angle_and_flip( value0, vax, ang, doflip );

			BOOST_ASSERT( fabs(ang) < 0.00001 || vax.dot(axis) > 0.99999 );
			if( ang >  M_PI ) ang -= 2.0*M_PI;
			if( ang < -M_PI ) ang += 2.0*M_PI;
			// std::cout << lb << " " << ang << " " << ub << " /  " << nside << " " << aa.axis().transpose() << " " << aa.angle() << std::endl;
			BOOST_ASSERT( lb <= ang && ang <= ub );
			Float p = (ang-lb)/(ub-lb) * (Float)nside;
			cell_index = (Index)p;
			params[0] = p - cell_index;
			BOOST_ASSERT( cell_index < nside );
			cell_index += doflip ? nside : 0;
			BOOST_ASSERT( 0 <= params[0] && params[0] <= 1 );
			return true;
		}

		///@brief get parameter space repr of Value for particular cell
		///@note necessary only for neighbor lookup
		void value_to_params_for_cell(
			Value const & value,
			Params & params
		) const {
			std::cerr << "Not Implemented" << std::endl;
			std::exit(-1);
		}

		///@brief return the cell_index of neighboring cells within radius of value
		///@note delta parameter is in "Parameter Space"
		template<class OutIter>
		void get_neighboring_cells(Value const & value, Float radius, OutIter out) const {
			std::cerr << "Not Implemented" << std::endl;
			std::exit(-1);
		}

		///@brief aka covering radius max distance from bin center to any value within bin
		Float bin_circumradius(Index resl) const {
			return (ub-lb) / nside / (Float)(1<<resl);
		}

		///@brief maximum distance from the bin center which must be within the bin
		Float bin_inradius(Index resl) const {
			return (ub-lb) / nside / (Float)(1<<resl);
		}

		///@brief cell size
		Index num_cells() const { return nside * ( flipaxis==V(0,0,0)? 1 : 2 ); }

	};

}}}

#endif

ext: hh

max_stars_repo_name: YaoYinYing/rifdock

max_issues_repo_name: YaoYinYing/rifdock

max_forks_repo_name: YaoYinYing/rifdock


text:
/***************************************************************************
   Copyright 2015 Ufora Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
****************************************************************************/
#pragma once

#include <typeinfo>
#include <boost/unordered_map.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

class ArbitraryTypeMap {
public:
	ArbitraryTypeMap()
		{
		}

	~ArbitraryTypeMap();

	ArbitraryTypeMap(const ArbitraryTypeMap& in);

	ArbitraryTypeMap& operator=(const ArbitraryTypeMap& in);

	size_t size() const
		{
		return mInstances.size();
		}

	template<class T>
	T& get()
		{
		static bool isInitialized = false;

		void* tname = (void*)typeid(T).name();

		if (!isInitialized)
			{
			boost::mutex::scoped_lock lock(mFunctionsMutex);

			mDestructors[tname] = boost::bind(&destroy<T>, boost::arg<1>());

			mDuplicators[tname] = boost::bind(&duplicate<T>, boost::arg<1>());
			}

		if (mInstances.find(tname) == mInstances.end())
			mInstances[tname] = (void*)new T();

		return *(T*)mInstances[tname];
		}

	template<class T>
	void erase()
		{
		void* tname = (void*)typeid(T).name();

		auto it = mInstances.find(tname);

		if (it == mInstances.end())
			return;

		void* value = it->second;
		mInstances.erase(it);

		boost::mutex::scoped_lock lock(mFunctionsMutex);
		mDestructors[tname](value);
		}

	void clear()
		{
		*this = ArbitraryTypeMap();
		}

private:
	template<class T>
	static void* duplicate(void* inValue)
		{
		return (void*)new T(*(T*)inValue);
		}

	template<class T>
	static void destroy(void* inValue)
		{
		((T*)inValue)->~T();
		}

	boost::unordered_map<void*, void*> mInstances;

	static boost::mutex mFunctionsMutex;

	static boost::unordered_map<void*, boost::function1<void, void*> > mDestructors;

	static boost::unordered_map<void*, boost::function1<void*, void*> > mDuplicators;
};

ext: hpp

max_stars_repo_name: ufora/ufora


text:
#include <vector>
#include <icetray/serialization.h>
#include <dataclasses/physics/I3DOMLaunch.h>
#include <dataclasses/physics/DeltaCompressor.h>
#include <stdexcept>
#include <dataclasses/I3Vector.h>
#include <boost/foreach.hpp>

I3DOMLaunch::I3DOMLaunch()
  : startTime_(0.0),
    trigger_(TEST_PATTERN),
    mode_(UNDEFINED),
    whichATWD_(UNKNOWN_CHIP),
    rawATWDChargeStamp_(0),
    whichATWDChargeStamp_(0),
    localCoincidence_(false),
    pedestal_(false)
{
  rawATWD_.resize(4);
}

I3DOMLaunch::~I3DOMLaunch() {}

template <class Archive>
void I3DOMLaunch::save(Archive& ar, unsigned version) const
{
  ar & make_nvp("StartTime", startTime_);

  ar & make_nvp("TriggerType", trigger_);
  ar & make_nvp("TriggerSituation", mode_);

  ar & make_nvp("WhichATWD", whichATWD_);

  // since version 3 of the file the raw waveforms are stored in delta
  // compressed form. This is only done, if archived to a non XML archive,
  // to allow to inspect the waveforms with dataio_shovel.
  if(  ( typeid(ar) != typeid(icecube::archive::xml_oarchive) ) ){
    try{
      I3DeltaCompression::DeltaCompressor compressor;
      std::vector< std::vector<unsigned int> > compressedATWD;

      std::vector<std::vector<int> >::const_iterator it;
      for( it = rawATWD_.begin(); it < rawATWD_.end(); it++ ){
        // reset the compressor and compresse the waveform
        compressor.reset();
        compressor.compress( *it );

        // copy the compressed ATWD waveform to the compressed std::vector and
        // add the std::vector to the fector of compressed ATWD waveforms.
        const std::vector<unsigned int>& compVals = compressor.getCompressed();
        std::vector<unsigned int> compVector( compVals.begin(), compVals.end() );
        compressedATWD.push_back( compVector );
      }
      // serialize all compressed ATWD waveforms
      ar & make_nvp("CompressedATWD", compressedATWD);

      // also write the number of samples for each ATWD waveform to the archive
      // as the decompressed waveforms need to be truncated from extra values
      // which are appended as the algorithm doesn't allow for a end marker.
      for( it = rawATWD_.begin(); it < rawATWD_.end(); it++ ){
        int numSamples = static_cast<int>( (*it).size() );
        ar & make_nvp( "NumSamplesATWD", numSamples );
      }

      // reset the compressor and compresse the waveform
      compressor.reset();
      compressor.compress( rawFADC_ );

      // copy the compressed waveform to the output std::vector and serialize this
      // std::vector with the compressed FADC waveform.
      const std::vector<unsigned int>& compVals = compressor.getCompressed();
      std::vector<unsigned int> compressedFADC( compVals.begin(), compVals.end() );
      ar & make_nvp("CompressedFADC", compressedFADC );

      // also write the number of samples for this waveform to the archive
      // as the decompressed waveform needs to be truncated from extra values
      // which are appended as the algorithm doesn't allow for a end marker.
      int numSamples =  rawFADC_.size();
      ar & make_nvp("NumSamplesFADC", numSamples );
    }
    catch( const std::domain_error& ex ) {
      log_fatal("%s", ex.what());
    }
  }else{
    // since the serialization method is split we only need to
    // worry about the load method so we can read old I3Vector data
    ar & make_nvp("RawATWD", rawATWD_);
    ar & make_nvp("RawFADC", rawFADC_);
  }
  ar & make_nvp("LocalCoincidence", localCoincidence_);
  ar & make_nvp("RawChargeStamp", rawChargeStamp_);
  ar & make_nvp("Pedestal", pedestal_);
  ar & make_nvp("ChargeStampHighestSample", chargeStampHighestSample_);
  ar & make_nvp("RawATWDChargeStamp", rawATWDChargeStamp_);
  ar & make_nvp("WhichATWDChargeStamp", whichATWDChargeStamp_);
}

template <class Archive>
void I3DOMLaunch::load(Archive& ar, unsigned version)
{
  ar & make_nvp("StartTime", startTime_);
  // ignore the "Trigger" information of old data
  if(version < 1)
  {
    int tmp;
    ar & make_nvp("Trigger", tmp);
  }
  // for version > 0 there is a trigger type and mode to be serialized
  if(version > 0)
  {
    ar & make_nvp("TriggerType", trigger_);
    ar & make_nvp("TriggerSituation", mode_);
  }
  // for version <= 0 there is no trigger type and mode available
  // use default values instead
  else
  {
    trigger_ = TEST_PATTERN;
    mode_ = UNDEFINED;
  }
  ar & make_nvp("WhichATWD", whichATWD_);

  // since version 3 of the file the raw waveforms are stored in delta
  // compressed form. This is only done, if archived to a non XML archive,
  // to allow to inspect the waveforms with dataio_shovel.
  if( ( version > 2 )
      &&
      ( typeid(ar) != typeid(icecube::archive::xml_iarchive) ) )
  {
    try
    {
      I3DeltaCompression::DeltaCompressor compressor;

      // Create the data structure for the compressed version
      // of the waveforms and deserialize fro the archive
      std::vector< std::vector<unsigned int> > compressedATWD( rawATWD_.size() );
      ar & make_nvp("CompressedATWD", compressedATWD);

      std::vector< std::vector<unsigned int> >::const_iterator it;
      std::vector<std::vector<int> >::iterator it2 = rawATWD_.begin();
      for( it = compressedATWD.begin(); it < compressedATWD.end(); it++, it2++ )
      {
        // reset compressor and initialize with the compressed data.
        compressor.reset();
        compressor.setCompressed( *it );

        // clear the rawATWD_ waveform and fill it with the decompressed values.
        (*it2).clear();
        compressor.decompress( dynamic_cast< std::vector<int>& >(*it2) );

        // get the number of real samples of the waveform and truncate any
        // extra values from the std::vector.
        unsigned int numSamples;
        ar & make_nvp( "NumSamplesATWD", numSamples );
	if (numSamples > it2->size())
	  {
	    log_fatal("error delta decompressing");
	  }

        (*it2).resize( numSamples );
      }

      std::vector<unsigned int> compressedFADC;
      ar & make_nvp("CompressedFADC", compressedFADC);

      // reset compressor and initialize with the compressed data.
      compressor.reset();
      compressor.setCompressed( compressedFADC );

      // clear the rawFADC_ waveform and fill it with the decompressed values.
      rawFADC_.clear();
      compressor.decompress( rawFADC_ );

      // get the number of real samples of the waveform and truncate any
      // extra values from the std::vector.
      unsigned int numFADCSamples;
      ar & make_nvp("NumSamplesFADC", numFADCSamples);
	if (numFADCSamples > rawFADC_.size())
	  {
	    log_fatal("error delta decompressing");
	  }

      rawFADC_.resize(numFADCSamples);
    }
    catch( const std::domain_error& ex )
    {
      log_fatal("%s", ex.what());
    }
  }
  else
  {
    if(version > 4){
      ar & make_nvp("RawATWD", rawATWD_);
      ar & make_nvp("RawFADC", rawFADC_);
    }else{
      // need to deserialize I3Vectors and translate to std::vector
      I3Vector< I3Vector<int> > tempRawATWD;
      ar & make_nvp("RawATWD", tempRawATWD);
      //need to clear the vectors before filling them
      rawATWD_.clear();
      BOOST_FOREACH(I3Vector<int>& wf, tempRawATWD){
	std::vector<int> tempWF;
	BOOST_FOREACH(int i, wf) tempWF.push_back(i);
	rawATWD_.push_back(tempWF);
      }

      //need to clear the vectors before filling them
      I3Vector<int> tempRawFADC;
      ar & make_nvp("RawFADC", tempRawFADC);
      rawFADC_.clear();
      BOOST_FOREACH(int i, tempRawFADC)
	rawFADC_.push_back(i);
    }
  }
  ar & make_nvp("LocalCoincidence", localCoincidence_);
  if( version > 4){
    ar & make_nvp("RawChargeStamp", rawChargeStamp_);
  }else{
    I3Vector<int> tempRawChargeStamp;
    ar & make_nvp("RawChargeStamp", tempRawChargeStamp);
    rawChargeStamp_.clear();
    BOOST_FOREACH(int i, tempRawChargeStamp)
      rawChargeStamp_.push_back(i);
  }
  if(version > 2)
    {
      ar & make_nvp("Pedestal", pedestal_);
    }
  // ignore the range for the raw charge stamp of old data
  if(version < 2)
  {
    bool tmp;
    ar & make_nvp("ChargeStampRange", tmp);
  }
  // for version > 1 there is an index to be serialized,
  // addressing the highest sample of the charge stamp
  if(version > 1)
  {
    ar & make_nvp("ChargeStampHighestSample", chargeStampHighestSample_);
  }
  // for version <= 1 there is no index available
  // use a value of 0 instead - should be fine since rawChargeStamp_ is empty
  else
  {
    if(!rawChargeStamp_.empty()) log_warn("oops, coarse charge stamp is not empty");
    chargeStampHighestSample_ = 0u;
  }
  if(version>3)
    {
      ar & make_nvp("RawATWDChargeStamp", rawATWDChargeStamp_);
      ar & make_nvp("WhichATWDChargeStamp", whichATWDChargeStamp_);
    }
}

bool operator==(const I3DOMLaunch& lhs, const I3DOMLaunch& rhs){
  return ( lhs.GetStartTime() == rhs.GetStartTime() &&
	   lhs.GetTriggerType() == rhs.GetTriggerType() &&
	   lhs.GetTriggerMode() == rhs.GetTriggerMode() &&
	   lhs.GetWhichATWD() == rhs.GetWhichATWD() &&
	   lhs.GetRawATWD(0) == rhs.GetRawATWD(0) &&
	   lhs.GetRawATWD(1) == rhs.GetRawATWD(1) &&
	   lhs.GetRawATWD(2) == rhs.GetRawATWD(2) &&
	   lhs.GetRawATWD(3) == rhs.GetRawATWD(3) &&
	   lhs.GetRawFADC() == rhs.GetRawFADC() &&
	   lhs.GetLCBit() == rhs.GetLCBit() &&
	   lhs.GetIsPedestalSub() == rhs.GetIsPedestalSub() &&
	   lhs.GetRawChargeStamp() == rhs.GetRawChargeStamp() &&
	   lhs.GetChargeStampHighestSample() == rhs.GetChargeStampHighestSample() );
}

std::ostream& I3DOMLaunch::Print(std::ostream& oss) const
{
    oss << "[ I3DOMLaunch :\n"
    << "    StartTime : " << GetStartTime() << '\n'
    << "        LCBit : " << GetLCBit() << '\n'
    << "]" ;

    return oss;
}

std::ostream& operator<<(std::ostream& oss, const I3DOMLaunch& d)
{
    return(d.Print(oss));
}

I3_SPLIT_SERIALIZABLE(I3DOMLaunch);

I3_SERIALIZABLE(I3DOMLaunchSeriesMap);


text:
/*
	This file is part of solidity.

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

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

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * Some useful snippets for the optimiser.
 */

#include <libyul/Utilities.h>

#include <libyul/AsmData.h>
#include <libyul/Exceptions.h>

#include <libsolutil/CommonData.h>
#include <libsolutil/FixedHash.h>

#include <boost/algorithm/string.hpp>

#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>

using namespace std;
using namespace solidity;
using namespace solidity::yul;
using namespace solidity::util;

string solidity::yul::reindent(string const& _code)
{
	int constexpr indentationWidth = 4;

	auto const static countBraces = [](string const& _s) noexcept -> int
	{
		auto const i = _s.find("//");
		auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast<ptrdiff_t>(i));
		auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; });
		auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; });
		return opening - closing;
	};

	vector<string> lines;
	boost::split(lines, _code, boost::is_any_of("\n"));
	for (string& line: lines)
		boost::trim(line);

	// Reduce multiple consecutive empty lines.
	lines = fold(lines, vector<string>{}, [](auto&& _lines, auto&& _line) {
		if (!(_line.empty() && !_lines.empty() && _lines.back().empty()))
			_lines.emplace_back(std::move(_line));
		return std::move(_lines);
	});

	stringstream out;
	int depth = 0;

	for (string const& line: lines)
	{
		int const diff = countBraces(line);
		if (diff < 0)
			depth += diff;

		if (!line.empty())
		{
			for (int i = 0; i < depth * indentationWidth; ++i)
				out << ' ';
			out << line;
		}
		out << '\n';

		if (diff > 0)
			depth += diff;
	}

	return out.str();
}

u256 solidity::yul::valueOfNumberLiteral(Literal const& _literal)
{
	yulAssert(_literal.kind == LiteralKind::Number, "Expected number literal!");

	std::string const& literalString = _literal.value.str();
	yulAssert(isValidDecimal(literalString) || isValidHex(literalString), "Invalid number literal!");
	return u256(literalString);
}

u256 solidity::yul::valueOfStringLiteral(Literal const& _literal)
{
	yulAssert(_literal.kind == LiteralKind::String, "Expected string literal!");
	yulAssert(_literal.value.str().size() <= 32, "Literal string too long!");

	return u256(h256(_literal.value.str(), h256::FromBinary, h256::AlignLeft));
}

u256 yul::valueOfBoolLiteral(Literal const& _literal)
{
	yulAssert(_literal.kind == LiteralKind::Boolean, "Expected bool literal!");

	if (_literal.value == "true"_yulstring)
		return u256(1);
	else if (_literal.value == "false"_yulstring)
		return u256(0);

	yulAssert(false, "Unexpected bool literal value!");
}

u256 solidity::yul::valueOfLiteral(Literal const& _literal)
{
	switch (_literal.kind)
	{
		case LiteralKind::Number:
			return valueOfNumberLiteral(_literal);
		case LiteralKind::Boolean:
			return valueOfBoolLiteral(_literal);
		case LiteralKind::String:
			return valueOfStringLiteral(_literal);
		default:
			yulAssert(false, "Unexpected literal kind!");
	}
}

template<>
bool Less<Literal>::operator()(Literal const& _lhs, Literal const& _rhs) const
{
	if (std::make_tuple(_lhs.kind, _lhs.type) != std::make_tuple(_rhs.kind, _rhs.type))
		return std::make_tuple(_lhs.kind, _lhs.type) < std::make_tuple(_rhs.kind, _rhs.type);

	if (_lhs.kind == LiteralKind::Number)
		return valueOfNumberLiteral(_lhs) < valueOfNumberLiteral(_rhs);
	else
		return _lhs.value < _rhs.value;
}

bool SwitchCaseCompareByLiteralValue::operator()(Case const* _lhs, Case const* _rhs) const
{
	yulAssert(_lhs && _rhs, "");
	return Less<Literal*>{}(_lhs->value.get(), _rhs->value.get());
}


text:
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//
#define BOOST_TEST_MODULE UnitTests
#include <boost/test/unit_test.hpp>

#include "UnitTests.hpp"

struct ConfigureLoggingFixture
{
    ConfigureLoggingFixture()
    {
        ConfigureLoggingTest();
    }
};

BOOST_GLOBAL_FIXTURE(ConfigureLoggingFixture);

// On Windows, duplicate the boost test logging output to the Visual Studio output window using OutputDebugString.
#if defined(_MSC_VER)

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/tee.hpp>
#include <iostream>
#include <Windows.h>

using namespace boost::iostreams;
using namespace std;

struct DebugOutputSink : boost::iostreams::sink
{
    std::streamsize write(const char* s, std::streamsize n)
    {
        // The given string is not null-terminated, so we need to copy it.
        std::string s2(s, boost::numeric_cast<size_t>(n));
        OutputDebugString(s2.c_str());
        return n;
    }
};

class SetupDebugOutput
{
public:
    SetupDebugOutput()
    {
        // Send the output to both cout (as standard) and the debug output.
        m_OutputStream.push(tee(std::cout));
        m_OutputStream.push(m_DebugOutputSink);

        boost::unit_test::unit_test_log.set_stream(m_OutputStream);
    }
private:
    filtering_ostream m_OutputStream;
    DebugOutputSink m_DebugOutputSink;
};

BOOST_GLOBAL_FIXTURE(SetupDebugOutput);

#endif // defined(_MSC_VER)


text:
#pragma once
#ifndef __Message_h__
#define __Message_h__

#include <chrono>

#include <boost/interprocess/managed_shared_memory.hpp>

#include "BasicTypes.h"

typedef U32 MessageId;

template<typename TData>
struct Message
{
public:
	bool ExpectsResponse() { return _ExpectsResponse; }
    MessageId Id() { return _Id; }

public:
    TData Data;
    void* Payload;
    U32 PayloadSize;

public:
    std::chrono::duration<double> GetLatency()
    {
        return std::chrono::duration_cast<std::chrono::duration<double>>(_ResponseTime - _SubmitTime);
    }

private:
    boost::interprocess::managed_shared_memory::handle_t _PayloadHandle;
    MessageId _Id;
    bool _ExpectsResponse;

    std::chrono::high_resolution_clock::time_point _SubmitTime;
    std::chrono::high_resolution_clock::time_point _ResponseTime;

    template<typename TData> friend class MessageBaseService;
    template<typename TData> friend class MessageClient;
    template<typename TData> friend class MessageServer;
};

#endif

max_stars_repo_name: hai-tran/SsdSim

max_issues_repo_name: hai-tran/SsdSim

max_forks_repo_name: hai-tran/SsdSim


text: #include <boost/date_time/constrained_value.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#include "Engine.h"
#include "Config.h"
#include "Normalize.h"
#include <boost/algorithm/string/join.hpp>
#include <gis/Box.h>
#include <gis/CoordinateTransformation.h>
#include <gis/Host.h>
#include <gis/OGR.h>
#include <gis/PostGIS.h>
#include <gis/OGRSpatialReferenceFactory.h>
#include <gis/CoordinateMatrixCache.h>
#include <macgyver/Exception.h>
#include <macgyver/StringConversion.h>
#include <spine/Reactor.h>
#include <gdal_version.h>
#include <memory>
#include <ogrsf_frmts.h>
#include <stdexcept>

const auto featuredeleter = [](OGRFeature* p) { OGRFeature::DestroyFeature(p); };
using SafeFeature = std::unique_ptr<OGRFeature, decltype(featuredeleter)>;

namespace SmartMet
{
namespace Engine
{
namespace Gis
{
namespace
{
int getEpsgCode(const GDALDataPtr& connection,
                const std::string& schema,
                const std::string& table,
                const std::string& geometry_column,
                const SmartMet::Engine::Gis::Config& config)
{
  try
  {
    auto layerdeleter = [&](OGRLayer* p) { connection->ReleaseResultSet(p); };
    using SafeLayer = std::unique_ptr<OGRLayer, decltype(layerdeleter)>;

    std::string sqlStmt =
        "select st_srid(" + geometry_column + ") from " + schema + "." + table + " limit 1;";

    SafeLayer pLayer(connection->ExecuteSQL(sqlStmt.c_str(), nullptr, nullptr), layerdeleter);

    if (!pLayer)
      throw Fmi::Exception(BCP, "Gis-engine: PostGIS metadata query failed: '" + sqlStmt + "'");

    SafeFeature pFeature(pLayer->GetNextFeature(), featuredeleter);

    if (pFeature)
      return pFeature->GetFieldAsInteger(0);

    if (config.getDefaultEPSG())
    {
      if (!config.quiet())
        std::cerr << "Warning: sqlStmt returned null. Setting EPSG to default value "
                  << *config.getDefaultEPSG() << std::endl;
      return *config.getDefaultEPSG();
    }

    throw Fmi::Exception(BCP, "Gis-engine: Null feature received from " + sqlStmt);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

GDALDataPtr db_connection(const Config& config, const std::string& pgname)
{
  try
  {
    // Read it from the database
    const postgis_connection_info& pgci = config.getPostGISConnectionInfo(pgname);

    Fmi::Host host(pgci.host, pgci.database, pgci.username, pgci.password, pgci.port);

    return host.connect();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}
}  // namespace

// ----------------------------------------------------------------------
/*!
 * \brief Create cache-keys for the map options
 */
// ----------------------------------------------------------------------

std::pair<std::string, std::string> cache_keys(const MapOptions& theOptions,
                                               const Fmi::SpatialReference* theSR)
{
  try
  {
    std::string wkt = "NULL";
    if (theSR)
      wkt = Fmi::OGR::exportToWkt(*theSR);

    std::string basic = theOptions.schema;
    basic += '|';
    basic += theOptions.table;
    basic += '|';
    basic += boost::algorithm::join(theOptions.fieldnames, "|");
    basic += '|';
    basic += (theOptions.where ? *theOptions.where : "");
    basic += '|';
    basic += wkt;

    std::string key = basic;
    key += '|';
    key += Fmi::to_string(theOptions.minarea ? *theOptions.minarea : 0.0);
    key += '|';
    key += Fmi::to_string(theOptions.mindistance ? *theOptions.mindistance : 0.0);

    return std::make_pair(basic, key);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

OGREnvelope Engine::getTableEnvelope(const GDALDataPtr& connection,
                                     const std::string& schema,
                                     const std::string& table,
                                     const std::string& geometry_column,
                                     bool quiet) const
{
  try
  {
    // we assume there is just one geometry column
    auto fixed_bbox = itsConfig->getTableBBox(schema, table);
    if (fixed_bbox)
    {
      OGREnvelope bbox;
      bbox.MinX = fixed_bbox->west;
      bbox.MinY = fixed_bbox->south;
      bbox.MaxX = fixed_bbox->east;
      bbox.MaxY = fixed_bbox->north;
      return bbox;
    }

#if 0
    std::string sqlStmt = "SELECT ST_EstimatedExtent('" + schema + "', '" + table + "', '" +
                          geometry_column + "')::geometry as extent";
#else
    std::string sqlStmt = "SELECT ST_Extent(" + geometry_column + ")::geometry as extent FROM " +
                          schema + "." + table;
#endif

    auto layerdeleter = [&](OGRLayer* p) { connection->ReleaseResultSet(p); };
    using SafeLayer = std::unique_ptr<OGRLayer, decltype(layerdeleter)>;

    SafeLayer pLayer(connection->ExecuteSQL(sqlStmt.c_str(), nullptr, nullptr), layerdeleter);

    if (!pLayer)
      throw Fmi::Exception(BCP, "Gis-engine: PostGIS metadata query failed: '" + sqlStmt + "'");

    SafeFeature pFeature(pLayer->GetNextFeature(), featuredeleter);

    if (!pFeature)
      throw Fmi::Exception(BCP, "Gis-engine: PostGIS feature query failed: '" + sqlStmt + "'");

    // get geometry
    OGRGeometry* pGeometry = pFeature->GetGeometryRef();

    if (!pGeometry)
    {
      Fmi::Exception ex(BCP, "Gis-engine: PostGIS feature query failed: '" + sqlStmt + "'");
      if (quiet)
        ex.disableLogging();
      throw ex;
    }

    OGREnvelope bbox;
    pGeometry->getEnvelope(&bbox);

    return bbox;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief The only permitted constructor requires a configfile
 */
// ----------------------------------------------------------------------

Engine::Engine(const std::string& theFileName) : itsConfigFile(theFileName) {}

// ----------------------------------------------------------------------
/*!
 * \brief Initialize the engine
 *
 * Note: We do not wish to delay the initialization of other engines.
 * init() is done in its own thread, hence we read the configuration
 * files here, and hence itsConfig is a pointer instead of an object.
 */
// ----------------------------------------------------------------------

void Engine::init()
{
  try
  {
    itsConfig.reset(new Config(itsConfigFile));

    itsCache.resize(itsConfig->getMaxCacheSize());
    itsFeaturesCache.resize(itsConfig->getMaxCacheSize());
    itsEnvelopeCache.resize(itsConfig->getMaxCacheSize());

    // Register all drivers just once

#if GDAL_VERSION_MAJOR < 2
    OGRRegisterAll();
#else
    GDALAllRegister();
#endif
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Shutdown the engine
 */
// ----------------------------------------------------------------------

void Engine::shutdown()
{
  std::cout << "  -- Shutdown requested (gis)\n";
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the CRS registry
 */
// ----------------------------------------------------------------------

Spine::CRSRegistry& Engine::getCRSRegistry()
{
  try
  {
    return itsConfig->getCRSRegistry();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Fetch a shape from the database
 *
 * \param theOptions query options
 */
// ----------------------------------------------------------------------

OGRGeometryPtr Engine::getShape(const Fmi::SpatialReference* theSR,
                                const MapOptions& theOptions) const
{
  try
  {
    // Validate options
    if (theOptions.schema.empty())
      throw Fmi::Exception(BCP, "PostGIS database name missing from map query");
    if (theOptions.table.empty())
      throw Fmi::Exception(BCP, "PostGIS table name missing from map query");

    // Find simplified map from the cache

    auto keys = cache_keys(theOptions, theSR);
    const auto& basic_key = keys.first;
    const auto& full_key = keys.second;

    auto obj = itsCache.find(full_key);
    if (obj)
      return *obj;

    // Find full map from the cache

    OGRGeometryPtr geom;

    obj = itsCache.find(basic_key);
    if (obj)
      geom = *obj;
    else
    {
      // Read it from the database
      auto connection = db_connection(*itsConfig, theOptions.pgname);

      std::string name = theOptions.schema + "." + theOptions.table;
      geom = Fmi::PostGIS::read(theSR, connection, name, theOptions.where);

      // Cache the result if it's not empty
      if (geom)
        itsCache.insert(basic_key, geom);
    }

    // If no simplification was requested we're done
    if (!theOptions.minarea && !theOptions.mindistance)
      return geom;

    // Apply simplification options

    if (theOptions.minarea)
      geom.reset(Fmi::OGR::despeckle(*geom, *theOptions.minarea));

    if (theOptions.mindistance && geom)
    {
      const double kilometers_to_degrees = 1.0 / 110.0;  // one degree latitude =~ 110 km
      const double kilometers_to_meters = 1000;

      OGRSpatialReference* crs = geom->getSpatialReference();
      bool geographic = (crs ? crs->IsGeographic() : false);
      if (!geographic)
        geom.reset(
            geom->SimplifyPreserveTopology(kilometers_to_meters * (*theOptions.mindistance)));
      else
        geom.reset(
            geom->SimplifyPreserveTopology(kilometers_to_degrees * (*theOptions.mindistance)));
    }

    // Cache the result

    if (geom)
      itsCache.insert(full_key, geom);

    return geom;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

Fmi::Features Engine::getFeatures(const MapOptions& theOptions) const
{
  return getFeatures(nullptr, theOptions);
}

Fmi::Features Engine::getFeatures(const Fmi::SpatialReference& theSR,
                                  const MapOptions& theOptions) const
{
  return getFeatures(&theSR, theOptions);
}

Fmi::Features Engine::getFeatures(const Fmi::SpatialReference* theSR,
                                  const MapOptions& theOptions) const
{
  try
  {
    // Validate options
    if (theOptions.schema.empty())
      throw Fmi::Exception(BCP, "PostGIS database name missing from map query");
    if (theOptions.table.empty())
      throw Fmi::Exception(BCP, "PostGIS table name missing from map query");

    // Find simplified map from the cache
    auto keys = cache_keys(theOptions, theSR);
    const auto& basic_key = keys.first;
    const auto& full_key = keys.second;

    auto obj = itsFeaturesCache.find(full_key);
    if (obj)
      return *obj;

    Fmi::Features ret;

    // Find full map from the cache
    obj = itsFeaturesCache.find(basic_key);
    if (obj)
    {
      ret = *obj;
    }
    else
    {
      // Read it from the database
      auto connection = db_connection(*itsConfig, theOptions.pgname);

      std::string name = theOptions.schema + "." + theOptions.table;
      ret = Fmi::PostGIS::read(theSR, connection, name, theOptions.fieldnames, theOptions.where);

      // Cache the result if it's not empty
      if (!ret.empty())
        itsFeaturesCache.insert(basic_key, ret);
    }

    // If no simplification was requested we're done
    if (!theOptions.minarea && !theOptions.mindistance)
      return ret;

    // Apply simplification options

    Fmi::Features newfeatures;
    for (const auto& feature : ret)
    {
      Fmi::FeaturePtr newfeature;
      if (theOptions.minarea)
        newfeature->geom.reset(Fmi::OGR::despeckle(*(feature->geom), *theOptions.minarea));

      if (theOptions.mindistance && newfeature->geom)
      {
        const double kilometers_to_degrees = 1.0 / 110.0;  // one degree latitude =~ 110 km
        const double kilometers_to_meters = 1000;

        OGRSpatialReference* crs = newfeature->geom->getSpatialReference();
        bool geographic = (crs ? crs->IsGeographic() : false);

        if (!geographic)
          newfeature->geom.reset(newfeature->geom->SimplifyPreserveTopology(
              kilometers_to_meters * (*theOptions.mindistance)));
        else
          newfeature->geom.reset(newfeature->geom->SimplifyPreserveTopology(
              kilometers_to_degrees * (*theOptions.mindistance)));
      }

      if (newfeature->geom)
        newfeatures.push_back(newfeature);
    }

    // Cache the result
    if (!newfeatures.empty())
      itsFeaturesCache.insert(full_key, newfeatures);

    return newfeatures;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Fetch meta data (timesteps and bounding box) from db
 *
 * \param theOptions query options
 */
// ----------------------------------------------------------------------

MetaData Engine::getMetaData(const MetaDataQueryOptions& theOptions) const
{
  try
  {
    MetaData metadata;

    auto connection = db_connection(*itsConfig, theOptions.pgname);

    // Get time always in UTC
    connection->ExecuteSQL("SET TIME ZONE UTC", nullptr, nullptr);

    auto layerdeleter = [&](OGRLayer* p) { connection->ReleaseResultSet(p); };
    using SafeLayer = std::unique_ptr<OGRLayer, decltype(layerdeleter)>;

    // 1) Get timesteps
    if (theOptions.time_column)
    {
      auto timestep = itsConfig->getTableTimeStep(theOptions.schema, theOptions.table);
      if (!timestep)
      {
        // List all available times
        std::string sqlStmt = "SELECT DISTINCT(" + *theOptions.time_column + ")" + " FROM " +
                              theOptions.schema + "." + theOptions.table + " WHERE " +
                              *theOptions.time_column + " IS NOT NULL ORDER by " +
                              *theOptions.time_column;

        SafeLayer pLayer(connection->ExecuteSQL(sqlStmt.c_str(), nullptr, nullptr), layerdeleter);

        if (!pLayer)
          throw Fmi::Exception(BCP, "Gis-engine: PostGIS metadata query failed: '" + sqlStmt + "'");

        while (true)
        {
          SafeFeature pFeature(pLayer->GetNextFeature(), featuredeleter);
          if (!pFeature)
            break;

          tm timeinfo;

          bool ret = pFeature->GetFieldAsDateTime(0,
                                                  &timeinfo.tm_year,
                                                  &timeinfo.tm_mon,
                                                  &timeinfo.tm_mday,
                                                  &timeinfo.tm_hour,
                                                  &timeinfo.tm_min,
                                                  &timeinfo.tm_sec,
                                                  &timeinfo.tm_isdst);

          if (!ret)
          {
            std::cout << "Reading values from '" << theOptions.schema << "." << theOptions.table
                      << "." << *theOptions.time_column << "' failed!" << std::endl;
            break;
          }

          timeinfo.tm_year -= 1900;  // years after 1900
          timeinfo.tm_mon -= 1;      // months 0..11

          metadata.timesteps.push_back(boost::posix_time::ptime_from_tm(timeinfo));
        }
      }

      else
      {
        // Establish starttime and endtime
        std::string sqlStmt = "SELECT min(" + *theOptions.time_column + ") as mintime, max(" +
                              *theOptions.time_column + ") as maxtime FROM " + theOptions.schema +
                              "." + theOptions.table + " WHERE " + *theOptions.time_column +
                              " IS NOT NULL";

        SafeLayer pLayer(connection->ExecuteSQL(sqlStmt.c_str(), nullptr, nullptr), layerdeleter);

        if (!pLayer)
          throw Fmi::Exception(BCP, "Gis-engine: PostGIS metadata query failed: '" + sqlStmt + "'");

        SafeFeature pFeature(pLayer->GetNextFeature(), featuredeleter);

        if (!pFeature)
          throw Fmi::Exception(BCP, "Gis-engine: PostGIS feature query failed: '" + sqlStmt + "'");

        tm start_tm;
        tm end_tm;

        bool ret1 = pFeature->GetFieldAsDateTime(0,
                                                 &start_tm.tm_year,
                                                 &start_tm.tm_mon,
                                                 &start_tm.tm_mday,
                                                 &start_tm.tm_hour,
                                                 &start_tm.tm_min,
                                                 &start_tm.tm_sec,
                                                 &start_tm.tm_isdst);
        bool ret2 = pFeature->GetFieldAsDateTime(1,
                                                 &end_tm.tm_year,
                                                 &end_tm.tm_mon,
                                                 &end_tm.tm_mday,
                                                 &end_tm.tm_hour,
                                                 &end_tm.tm_min,
                                                 &end_tm.tm_sec,
                                                 &end_tm.tm_isdst);

        if (!ret1 || !ret2)
        {
          std::cout << "Reading values from '" << theOptions.schema << "." << theOptions.table
                    << "." << *theOptions.time_column << "' failed!" << std::endl;
        }
        else
        {
          start_tm.tm_year -= 1900;  // years after 1900
          start_tm.tm_mon -= 1;      // months 0..11

          end_tm.tm_year -= 1900;  // years after 1900
          end_tm.tm_mon -= 1;      // months 0..11

          auto starttime = boost::posix_time::ptime_from_tm(start_tm);
          auto endtime = boost::posix_time::ptime_from_tm(end_tm);
          metadata.timeinterval = TimeInterval{starttime, endtime, *timestep};
        }
      }
    }

    // 2) Get bounding box
    metadata.xmin = 0.0;
    metadata.ymin = 0.0;
    metadata.xmax = 0.0;
    metadata.ymax = 0.0;

    // Cache envelopes. We assume no need to reduce envelope sizes when old data is deleted
    auto hash = theOptions.hash_value();
    if (theOptions.time_column && !metadata.timesteps.empty())
    {
      const auto& last_time = metadata.timesteps.back();
      boost::hash_combine(hash, boost::hash_value(Fmi::to_iso_string(last_time)));
    }

    auto obj = itsEnvelopeCache.find(hash);
    if (obj)
    {
      metadata.xmin = obj->MinX;
      metadata.ymin = obj->MinY;
      metadata.xmax = obj->MaxX;
      metadata.ymax = obj->MaxY;
      return metadata;
    }

    OGREnvelope table_envelope = getTableEnvelope(connection,
                                                  theOptions.schema,
                                                  theOptions.table,
                                                  theOptions.geometry_column,
                                                  itsConfig->quiet());

    // convert source spatial reference system to EPSG:4326
    int epsg = getEpsgCode(
        connection, theOptions.schema, theOptions.table, theOptions.geometry_column, *itsConfig);

    Fmi::SpatialReference source(epsg);
    Fmi::SpatialReference target("WGS84");
    Fmi::CoordinateTransformation transformation(source, target);

    bool ok = (transformation.transform(table_envelope.MinX, table_envelope.MinY) &&
               transformation.transform(table_envelope.MaxX, table_envelope.MaxY));
    if (ok)
    {
      metadata.xmin = table_envelope.MinX;
      metadata.ymin = table_envelope.MinY;
      metadata.xmax = table_envelope.MaxX;
      metadata.ymax = table_envelope.MaxY;
    }

    itsEnvelopeCache.insert(hash, table_envelope);

    return metadata;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the bounding box for a EPSG
 */
// ----------------------------------------------------------------------

BBox Engine::getBBox(int theEPSG) const
{
  try
  {
    return itsConfig->getBBox(theEPSG);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return EPSG information
 */
// ----------------------------------------------------------------------

boost::optional<EPSG> Engine::getEPSG(int theEPSG) const
{
  try
  {
    return itsConfig->getEPSG(theEPSG);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

void Engine::populateGeometryStorage(const PostGISIdentifierVector& thePostGISIdentifiers,
                                     GeometryStorage& theGeometryStorage) const
{
  try
  {
    // If geometries with same name and type came from the same table (like roads) they are merged
    // into one. Geometries with same name and type came are not merged if they are from different
    // tables, for example same city can be in deffirent tables (like esri.europe_cities_eureffin
    // and natural_earth.world_populated_places)
    std::map<std::string, std::string> geomid_pgkey_map;

    // This set is to prevent multiple readings of the same data source
    // 'pgname:schema:table:field'
    std::set<std::string> pgKeys;

    for (auto pgId : thePostGISIdentifiers)
    {
      if (Spine::Reactor::isShuttingDown())
        return;

      std::string pgKey = pgId.key();

      if (pgKeys.find(pgKey) != pgKeys.end())
        continue;

      pgKeys.insert(pgKey);

      SmartMet::Engine::Gis::MapOptions mo;
      mo.pgname = pgId.pgname;
      mo.schema = pgId.schema;
      mo.table = pgId.table;
      mo.fieldnames.insert(pgId.field);

      Fmi::SpatialReference srs("WGS84");

      Fmi::Features features = getFeatures(srs, mo);

      for (const auto& feature : features)
      {
        const OGRGeometry* geom = feature->geom.get();

        if (geom != nullptr)
        {
          Fmi::Attribute attribute = feature->attributes.at(pgId.field);
          AttributeToString ats;
          std::string geomName = boost::apply_visitor(ats, attribute);
          geomName += pgId.source_name;

          // Geometry name can not be empty, since it is used for example in timesries queries
          // like 'place=helsinki'
          if (geomName.empty())
            continue;

          // Convert to lower case
          normalize_string(geomName);

          OGRwkbGeometryType geomType = geom->getGeometryType();

          std::string geom_id = (geomName + Fmi::to_string(static_cast<int>(geomType)));
          if (geomid_pgkey_map.find(geom_id) != geomid_pgkey_map.end())
          {
            if (geomid_pgkey_map.at(geom_id) != pgKey)
            {
              // Geom of the same type and source_name processed already
              continue;
            }

            if (geomType == wkbPoint)
            {
              // Skip POINT-geometry with the same name and type. For example city 'Brest' can be
              // found both in France and in Belarus. Other than POINT-geometries are
              // merged below, for example roads are stored in small sections and must be merged
              continue;
            }
          }
          else
          {
            // Geometry (name+type) encountered first time
            geomid_pgkey_map[geomName + Fmi::to_string(static_cast<int>(geomType))] = pgKey;
          }

          // If same name and type found
          if (theGeometryStorage.itsGeometries.find(geomType) ==
              theGeometryStorage.itsGeometries.end())
          {
            // If that type of geometries not found, add new one
            NameOGRGeometryMap nameOGRGeometryMap;
            nameOGRGeometryMap.insert(
                make_pair(geomName, boost::shared_ptr<OGRGeometry>(geom->clone())));
            theGeometryStorage.itsGeometries.insert(std::make_pair(geomType, nameOGRGeometryMap));
          }
          else
          {
            // That type of geometries found
            NameOGRGeometryMap& nameOGRGeometryMap = theGeometryStorage.itsGeometries[geomType];
            // If named area not found, add new one
            if (nameOGRGeometryMap.find(geomName) == nameOGRGeometryMap.end())
            {
              nameOGRGeometryMap.insert(
                  std::make_pair(geomName, boost::shared_ptr<OGRGeometry>(geom->clone())));
            }
            else
            {
              // Do the merge with the new and old one
              boost::shared_ptr<OGRGeometry>& previousGeom = nameOGRGeometryMap[geomName];
              if (geomType == wkbMultiLineString)
              {
                // Multilinestrings are merged with addGeometryDirectly-function
                auto* geom_tmp = dynamic_cast<OGRMultiLineString*>(previousGeom->clone());
                const auto* new_geom = dynamic_cast<const OGRMultiLineString*>(geom);
                // Iterate the LINESTRINGS inside Multilinestring and add them to old one
                for (int i = 0; i < new_geom->getNumGeometries(); i++)
                {
                  geom_tmp->addGeometryDirectly(new_geom->getGeometryRef(i)->clone());
                }
                previousGeom.reset(geom_tmp);
              }
              else
              {
                // For other geometries use Union-function
                previousGeom.reset(previousGeom->Union(geom));
              }
            }
          }

          std::string svgString = Fmi::OGR::exportToSvg(*geom, Fmi::Box::identity(), 6);

          if (geomType == wkbPolygon || geomType == wkbMultiPolygon)
          {
#ifdef MYDEBUG
            cout << "POLYGON in SVG format: " << svgString << endl;
#endif
            if (theGeometryStorage.itsPolygons.find(geomName) !=
                theGeometryStorage.itsPolygons.end())
              theGeometryStorage.itsPolygons[geomName] = svgString;
            else
              theGeometryStorage.itsPolygons.insert(std::make_pair(geomName, svgString));
          }
          else if (geomType == wkbLineString || geomType == wkbMultiLineString)
          {
#ifdef MYDEBUG
            std::cout << "LINE in SVG format: " << svgString << std::endl;
#endif
            if (theGeometryStorage.itsLines.find(geomName) != theGeometryStorage.itsLines.end())
            {
              theGeometryStorage.itsLines[geomName].append(svgString);
            }
            else
              theGeometryStorage.itsLines.insert(std::make_pair(geomName, svgString));
          }
          else if (geomType == wkbPoint)
          {
            const auto* ogrPoint = reinterpret_cast<const OGRPoint*>(geom);
            if (theGeometryStorage.itsPoints.find(geomName) != theGeometryStorage.itsPoints.end())
              theGeometryStorage.itsPoints[geomName] =
                  std::make_pair(ogrPoint->getX(), ogrPoint->getY());
            else
              theGeometryStorage.itsPoints.insert(
                  std::make_pair(geomName, std::make_pair(ogrPoint->getX(), ogrPoint->getY())));
          }
        }
      }
    }
    // Add quotation mark in the beginning and in the end
    for (auto& svg : theGeometryStorage.itsLines)
    {
      if (!svg.second.empty() && svg.second[0] != '"')
      {
        svg.second.insert(0, "\"");
        svg.second.append("\"");
      }
    }
    for (auto& svg : theGeometryStorage.itsPolygons)
    {
      if (!svg.second.empty() && svg.second[0] != '"')
      {
        svg.second.insert(0, "\"");
        svg.second.append("\"");
      }
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

Fmi::Cache::CacheStatistics Engine::getCacheStats() const
{
  Fmi::Cache::CacheStatistics ret;

  ret.insert(std::make_pair("Gis::geometry_cache", itsCache.statistics()));
  ret.insert(std::make_pair("Gis::features_cache", itsFeaturesCache.statistics()));
  ret.insert(std::make_pair("Gis::envelope_cache", itsEnvelopeCache.statistics()));
  ret.insert(std::make_pair("Gis::gis-library::projection_info_cache", Fmi::SpatialReference::getCacheStats()));
  ret.insert(std::make_pair("Gis::gis-library::spatial_reference_cache", Fmi::OGRSpatialReferenceFactory::getCacheStats()));
  ret.insert(std::make_pair("Gis::gis-library::coordinate_matrix_cache", Fmi::CoordinateMatrixCache::getCacheStats()));

  return ret;
}

}  // namespace Gis
}  // namespace Engine
}  // namespace SmartMet

// DYNAMIC MODULE CREATION TOOLS

extern "C" void* engine_class_creator(const char* configfile, void* /* user_data */)
{
  return new SmartMet::Engine::Gis::Engine(configfile);
}

extern "C" const char* engine_name()
{
  return "Gis";
}
// ======================================================================

max_stars_repo_name: fmidev/smartmet-engine-gis

max_issues_repo_name: fmidev/smartmet-engine-gis

max_forks_repo_name: fmidev/smartmet-engine-gis


text:
// Date Last Altered: $Date: 2008-12-01 13:34:05 -0700 (Mon, 01 Dec 2008) $
// Revision Number: $Revision: 423 $
//--------------------------------------------*-C++-*------------------------------------//
/*! \file FieldTest.cc
 *  \author Greg Davidson
 *  \date May 29, 2008
 *
 *  \brief Includes all of the unit tests for the Field Module
 *
 *  This file runs all of the unit tests for the Field Module by including all
 *  of the test suites defined in the include files. */

#define BOOST_TEST_MODULE FieldTest
#include <boost/test/included/unit_test.hpp>

#include "CartesianMesh1D.hh"
#include "Field.hh"

// Run the field tests
#include "FieldTest.hh"

ext: cc

max_stars_repo_name: jlconlin/PhDThesis

max_issues_repo_name: jlconlin/PhDThesis

max_forks_repo_name: jlconlin/PhDThesis