<commit_before>/*
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>
#include <QHostAddress>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/influxdb/influxdb9.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/influxdb/json_printer.hh"

using namespace com::centreon::broker::influxdb;

static const char* query_footer = "]}";

/**
 *  Constructor.
 */
influxdb9::influxdb9(
            std::string const& user,
            std::string const& passwd,
            std::string const& addr,
            unsigned short port,
            std::string const& db,
            std::string const& status_ts,
            std::vector<column> const& status_cols,
            std::string const& metric_ts,
            std::vector<column> const& metric_cols)
  : _host(addr),
    _port(port) {
  logging::debug(logging::medium)
    << "influxdb: connecting using 0.9 version protocol";

  // Try to connect to the server.
  _connect_socket();
  _socket->close();

  _create_queries(user, passwd, db, status_ts, status_cols, metric_ts, metric_cols);
}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
influxdb9::influxdb9(influxdb9 const& f) {
  influxdb::operator=(f);
}

/**
 *  Destructor.
 */
influxdb9::~influxdb9() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
influxdb9& influxdb9::operator=(influxdb9 const& f) {
  if (this != &f) {
    _query = f._query;
  }
  return (*this);
}

/**
 *  Clear the query.
 */
void influxdb9::clear() {
  _query.clear();
}

/**
 *  Write a metric to the query.
 *
 *  @param[in] m  The metric to write.
 */
void influxdb9::write(storage::metric const& m) {
  _query.append(_metric_query.generate_metric(m));
}

/**
 *  Write a status to the query.
 *
 *  @param[in] s  The status to write.
 */
void influxdb9::write(storage::status const& s) {
  _query.append(_status_query.generate_status(s));
}

/**
 *  Commit a query.
 */
void influxdb9::commit() {
  if (_query.empty())
    return ;

  // Remove trailing coma.
  _query[_query.size() - 1] = ' ';

  std::stringstream content_length;
  size_t length = _query.size() + _db_header.size() + ::strlen(query_footer);
  content_length << "Content-Length: " << length << "\n";

  std::string final_query;
  final_query.reserve(length + _post_header.size() + content_length.str().size() + 1);
  final_query
    .append(_post_header).append(content_length.str()).append("\n")
    .append(_db_header).append(_query).append(query_footer);

  _connect_socket();

  // Send the data to the server.
  if (_socket->write(final_query.c_str(), final_query.size())
        != final_query.size())
    throw (exceptions::msg()
      << "influxdb: couldn't commit data to influxdb with address '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': "
      << _socket->errorString());

  while (_socket->bytesToWrite() != 0) {
    if (_socket->waitForBytesWritten() == -1)
      throw (exceptions::msg()
        << "influxdb: couldn't send data to influxdb with address '"
        << _socket->peerAddress().toString()
        << "' and port '" << _socket->peerPort() << "': "
        << _socket->errorString());
  }

  // Receive the server answer.
  QString answer;
  while (true) {
    if (_socket->waitForReadyRead() == -1)
      throw (exceptions::msg()
        << "influxdb: couldn't receive influxdb answer with address '"
        << _socket->peerAddress().toString()
        << "' and port '" << _socket->peerPort() << "': "
        << _socket->errorString());

    answer.append(_socket->readAll());

    if (_check_answer_string(answer.toStdString()) == true)
      break;
  }
  _socket->close();
  _query.clear();
}

/**
 *  Connect the socket to the endpoint.
 */
void influxdb9::_connect_socket() {
  _socket.reset(new QTcpSocket);
  _socket->connectToHost(QString::fromStdString(_host), _port);
  if (!_socket->waitForConnected())
    throw exceptions::msg()
      << "influxdb: couldn't connect to influxdb with address '"
      << _host << "' and port '" << _port << "': " << _socket->errorString();
}

/**
 *  Check the server's answer.
 *
 *  @param[in] ans  The server's answer.
 *
 *  @return         True of the answer was complete, false otherwise.
 */
bool influxdb9::_check_answer_string(std::string const& ans) {
  size_t first_line = ans.find_first_of('\n');
  if (first_line == std::string::npos)
    return (false);
  std::string first_line_str = ans.substr(0, first_line);

  logging::debug(logging::medium)
    << "influxdb: received an answer from "
    << _socket->peerAddress().toString()
    << "' and port '" << _socket->peerPort() << "': '" << ans << "'";

  // Split the first line using the power of std.
  std::istringstream iss(first_line_str);
  std::vector<std::string> split;
  std::copy(
         std::istream_iterator<std::string>(iss),
         std::istream_iterator<std::string>(),
         std::back_inserter(split));

  if (split.size() != 3)
    throw (exceptions::msg()
      << "influxdb: unrecognizable HTTP header for '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': got '"
      << first_line_str << "'");

  if (split[0] == "HTTP/1.0" && split[1] == "200" && split[2] == "OK")
    return (true);
  else
    throw (exceptions::msg()
      << "influxdb: got an error from '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': '"
      << ans << "'");
}

/**
 *  Create the queries for influxdb.
 *
 *  @param[in] status_ts    Name of the timeseries status.
 *  @param[in] status_cols  Column for the statuses.
 *  @param[in] metric_ts    Name of the timeseries metric.
 *  @param[in] metric_cols  Column for the metrics.
 */
void influxdb9::_create_queries(
                  std::string const& user,
                  std::string const& passwd,
                  std::string const& db,
                  std::string const& status_ts,
                  std::vector<column> const& status_cols,
                  std::string const& metric_ts,
                  std::vector<column> const& metric_cols) {
  // Create POST HTTP header.
  std::string base_url;
  base_url
    .append("/write?u=").append(user)
    .append("&p=").append(passwd);
  _post_header.append("POST ").append(base_url).append(" HTTP/1.0\n");

  // Create influxdb header.
  json_printer p;
  p.open_object().add_string("database", db).open_array("points");
  _db_header.append(p.get_data());
  p.clear();

  // Create status query.
  p.open_object()
     .add_string("name", status_ts)
     .open_object("tags");
  for (std::vector<column>::const_iterator
         it(status_cols.begin()),
         end(status_cols.end());
       it != end; ++it)
    if (it->is_flag()) {
      if (it->get_type() == column::number)
        p.add_value(it->get_name(), it->get_value());
      else if (it->get_type() == column::string)
        p.add_string(it->get_name(), it->get_value());
    }
   p.close_object()
     .add_value("timestamp", "$TIME$")
     .open_object("fields");
   for (std::vector<column>::const_iterator
          it(status_cols.begin()),
          end(status_cols.end());
        it != end; ++it)
     if (!it->is_flag()) {
       if (it->get_type() == column::number)
         p.add_value(it->get_name(), it->get_value());
       else if (it->get_type() == column::string)
         p.add_string(it->get_name(), it->get_value());
     }
   p.close_object().close_object();
   _status_query = query(p.get_data(), query::status);
   p.clear();

   // Create metric query.
   p.open_object()
      .add_string("name", metric_ts)
      .open_object("tags");
   for (std::vector<column>::const_iterator
          it(metric_cols.begin()),
          end(metric_cols.end());
        it != end; ++it)
     if (it->is_flag())
       p.add_value(it->get_name(), it->get_value());
    p.close_object()
      .add_value("timestamp", "$TIME$")
      .open_object("fields");
    for (std::vector<column>::const_iterator
           it(metric_cols.begin()),
           end(metric_cols.end());
         it != end; ++it)
      if (!it->is_flag())
        p.add_value(it->get_name(), it->get_value());
    p.close_object().close_object();
    _metric_query = query(p.get_data(), query::metric);
}
<commit_msg>Influxdb: Fix waitFor* incorrect handling of errors.<commit_after>/*
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>
#include <QHostAddress>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/influxdb/influxdb9.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/influxdb/json_printer.hh"

using namespace com::centreon::broker::influxdb;

static const char* query_footer = "]}";

/**
 *  Constructor.
 */
influxdb9::influxdb9(
            std::string const& user,
            std::string const& passwd,
            std::string const& addr,
            unsigned short port,
            std::string const& db,
            std::string const& status_ts,
            std::vector<column> const& status_cols,
            std::string const& metric_ts,
            std::vector<column> const& metric_cols)
  : _host(addr),
    _port(port) {
  logging::debug(logging::medium)
    << "influxdb: connecting using 0.9 version protocol";

  // Try to connect to the server.
  _connect_socket();
  _socket->close();

  _create_queries(user, passwd, db, status_ts, status_cols, metric_ts, metric_cols);
}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
influxdb9::influxdb9(influxdb9 const& f) {
  influxdb::operator=(f);
}

/**
 *  Destructor.
 */
influxdb9::~influxdb9() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
influxdb9& influxdb9::operator=(influxdb9 const& f) {
  if (this != &f) {
    _query = f._query;
  }
  return (*this);
}

/**
 *  Clear the query.
 */
void influxdb9::clear() {
  _query.clear();
}

/**
 *  Write a metric to the query.
 *
 *  @param[in] m  The metric to write.
 */
void influxdb9::write(storage::metric const& m) {
  _query.append(_metric_query.generate_metric(m));
}

/**
 *  Write a status to the query.
 *
 *  @param[in] s  The status to write.
 */
void influxdb9::write(storage::status const& s) {
  _query.append(_status_query.generate_status(s));
}

/**
 *  Commit a query.
 */
void influxdb9::commit() {
  if (_query.empty())
    return ;

  // Remove trailing coma.
  _query[_query.size() - 1] = ' ';

  std::stringstream content_length;
  size_t length = _query.size() + _db_header.size() + ::strlen(query_footer);
  content_length << "Content-Length: " << length << "\n";

  std::string final_query;
  final_query.reserve(length + _post_header.size() + content_length.str().size() + 1);
  final_query
    .append(_post_header).append(content_length.str()).append("\n")
    .append(_db_header).append(_query).append(query_footer);

  _connect_socket();

  // Send the data to the server.
  if (_socket->write(final_query.c_str(), final_query.size())
        != final_query.size())
    throw (exceptions::msg()
      << "influxdb: couldn't commit data to influxdb with address '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': "
      << _socket->errorString());

  while (_socket->bytesToWrite() != 0) {
    if (_socket->waitForBytesWritten() == false)
      throw (exceptions::msg()
        << "influxdb: couldn't send data to influxdb with address '"
        << _socket->peerAddress().toString()
        << "' and port '" << _socket->peerPort() << "': "
        << _socket->errorString());
  }

  // Receive the server answer.
  QString answer;
  while (true) {
    if (_socket->waitForReadyRead() == false)
      throw (exceptions::msg()
        << "influxdb: couldn't receive influxdb answer with address '"
        << _socket->peerAddress().toString()
        << "' and port '" << _socket->peerPort() << "': "
        << _socket->errorString());

    answer.append(_socket->readAll());

    if (_check_answer_string(answer.toStdString()) == true)
      break;
  }
  _socket->close();
  _query.clear();
}

/**
 *  Connect the socket to the endpoint.
 */
void influxdb9::_connect_socket() {
  _socket.reset(new QTcpSocket);
  _socket->connectToHost(QString::fromStdString(_host), _port);
  if (!_socket->waitForConnected())
    throw exceptions::msg()
      << "influxdb: couldn't connect to influxdb with address '"
      << _host << "' and port '" << _port << "': " << _socket->errorString();
}

/**
 *  Check the server's answer.
 *
 *  @param[in] ans  The server's answer.
 *
 *  @return         True of the answer was complete, false otherwise.
 */
bool influxdb9::_check_answer_string(std::string const& ans) {
  size_t first_line = ans.find_first_of('\n');
  if (first_line == std::string::npos)
    return (false);
  std::string first_line_str = ans.substr(0, first_line);

  logging::debug(logging::medium)
    << "influxdb: received an answer from "
    << _socket->peerAddress().toString()
    << "' and port '" << _socket->peerPort() << "': '" << ans << "'";

  // Split the first line using the power of std.
  std::istringstream iss(first_line_str);
  std::vector<std::string> split;
  std::copy(
         std::istream_iterator<std::string>(iss),
         std::istream_iterator<std::string>(),
         std::back_inserter(split));

  if (split.size() != 3)
    throw (exceptions::msg()
      << "influxdb: unrecognizable HTTP header for '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': got '"
      << first_line_str << "'");

  if (split[0] == "HTTP/1.0" && split[1] == "200" && split[2] == "OK")
    return (true);
  else
    throw (exceptions::msg()
      << "influxdb: got an error from '"
      << _socket->peerAddress().toString()
      << "' and port '" << _socket->peerPort() << "': '"
      << ans << "'");
}

/**
 *  Create the queries for influxdb.
 *
 *  @param[in] status_ts    Name of the timeseries status.
 *  @param[in] status_cols  Column for the statuses.
 *  @param[in] metric_ts    Name of the timeseries metric.
 *  @param[in] metric_cols  Column for the metrics.
 */
void influxdb9::_create_queries(
                  std::string const& user,
                  std::string const& passwd,
                  std::string const& db,
                  std::string const& status_ts,
                  std::vector<column> const& status_cols,
                  std::string const& metric_ts,
                  std::vector<column> const& metric_cols) {
  // Create POST HTTP header.
  std::string base_url;
  base_url
    .append("/write?u=").append(user)
    .append("&p=").append(passwd);
  _post_header.append("POST ").append(base_url).append(" HTTP/1.0\n");

  // Create influxdb header.
  json_printer p;
  p.open_object().add_string("database", db).open_array("points");
  _db_header.append(p.get_data());
  p.clear();

  // Create status query.
  p.open_object()
     .add_string("name", status_ts)
     .open_object("tags");
  for (std::vector<column>::const_iterator
         it(status_cols.begin()),
         end(status_cols.end());
       it != end; ++it)
    if (it->is_flag()) {
      if (it->get_type() == column::number)
        p.add_value(it->get_name(), it->get_value());
      else if (it->get_type() == column::string)
        p.add_string(it->get_name(), it->get_value());
    }
   p.close_object()
     .add_value("timestamp", "$TIME$")
     .open_object("fields");
   for (std::vector<column>::const_iterator
          it(status_cols.begin()),
          end(status_cols.end());
        it != end; ++it)
     if (!it->is_flag()) {
       if (it->get_type() == column::number)
         p.add_value(it->get_name(), it->get_value());
       else if (it->get_type() == column::string)
         p.add_string(it->get_name(), it->get_value());
     }
   p.close_object().close_object();
   _status_query = query(p.get_data(), query::status);
   p.clear();

   // Create metric query.
   p.open_object()
      .add_string("name", metric_ts)
      .open_object("tags");
   for (std::vector<column>::const_iterator
          it(metric_cols.begin()),
          end(metric_cols.end());
        it != end; ++it)
     if (it->is_flag())
       p.add_value(it->get_name(), it->get_value());
    p.close_object()
      .add_value("timestamp", "$TIME$")
      .open_object("fields");
    for (std::vector<column>::const_iterator
           it(metric_cols.begin()),
           end(metric_cols.end());
         it != end; ++it)
      if (!it->is_flag())
        p.add_value(it->get_name(), it->get_value());
    p.close_object().close_object();
    _metric_query = query(p.get_data(), query::metric);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Troels Blum <troels@blum.dk>
 *
 * This file is part of cphVB.
 *
 * cphVB 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.
 *
 * cphVB 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 cphVB. If not, see <http://www.gnu.org/licenses/>.
 */

#include <cstring>
#include <cassert>
#include "ArrayManager.hpp"
ArrayManager::ArrayManager() :
    arrayStore(new StaticStore<cphvb_array>(4096*10)) {}

cphvb_array* ArrayManager::create(cphvb_array* base,
                                  cphvb_type type,
                                  cphvb_intp ndim,
                                  cphvb_index start,
                                  cphvb_index shape[CPHVB_MAXDIM],
                                  cphvb_index stride[CPHVB_MAXDIM],
                                  cphvb_intp has_init_value,
                                  cphvb_constant init_value)
{
    cphvb_array* array = arrayStore->c_next();
    array->owner          = CPHVB_PARENT;
    array->base           = base;
    array->type           = type;
    array->ndim           = ndim;
    array->start          = start;
    array->has_init_value = has_init_value;
    array->init_value     = init_value;
    array->data           = NULL;
    array->ref_count      = 1;
    std::memcpy(array->shape, shape, ndim * sizeof(cphvb_index));
    std::memcpy(array->stride, stride, ndim * sizeof(cphvb_index));

    if(array->base != NULL)
    {
        assert(array->base->base == NULL);
        assert(!has_init_value);
        ++array->base->ref_count;
        array->data = array->base->data;
    }
    return array;
}

ArrayManager::~ArrayManager()
{
    delete arrayStore;
}

void ArrayManager::erasePending(cphvb_array* array)
{
    eraseQueue.push_back(array);
}

void ArrayManager::changeOwnerPending(cphvb_array* base,
                                      cphvb_comp owner)
{
    assert(base->base == NULL);
#ifdef _WIN32
	OwnerTicket t;
	t.array = base;
	t.owner = owner;
    ownerChangeQueue.push_back(t);
#else
    ownerChangeQueue.push_back((OwnerTicket){base,owner});
#endif
}

void ArrayManager::flush()
{
    std::pair<BaseToViewMMap::iterator,BaseToViewMMap::iterator> range;
    BaseToViewMMap::iterator rit;
    std::deque<OwnerTicket>::iterator oit = ownerChangeQueue.begin();

    //First we change ownership for all those pending
    for (; oit != ownerChangeQueue.end(); ++oit)
    {
        (*oit).array->owner = (*oit).owner;
        if ((*oit).array->base == NULL)
        {   //if it is a base array we check to see if there are stale views
            range = staleView.equal_range((*oit).array);
            for (rit=range.first; rit!=range.second; ++rit)
            {   //If there are any we delete them
                arrayStore->erase(rit->second);
                staleView.erase(rit);
            }
        }
    }
    // All ownerships are changed. So we clear the queue
    ownerChangeQueue.clear();

    //Then we delete arrays marked for deletion
    std::deque<cphvb_array*>::iterator eit = eraseQueue.begin();
    for (; eit != eraseQueue.end(); ++eit)
    {
        if ((*eit)->base == NULL)
        {   //We have to deallocate the base array because of the
            //triggering opcode CPHVB_DESTROY.
            cphvb_data_free((*eit));
            arrayStore->erase(*eit);
        }
        else if ((*eit)->base->owner == CPHVB_PARENT)
        {   //The base owner is up stream so we can delete it
            arrayStore->erase(*eit);
        }
        else
        {   //The base owner is down stream. So we postpone deletion
            staleView.insert(std::pair<cphvb_array*,
                                 cphvb_array*>((*eit)->base, *eit));
        }
    }
    // All erases have been delt with. So we clear the queue
    eraseQueue.clear();
}
<commit_msg>Fixed a problem with MultiMap erase<commit_after>/*
 * Copyright 2011 Troels Blum <troels@blum.dk>
 *
 * This file is part of cphVB.
 *
 * cphVB 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.
 *
 * cphVB 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 cphVB. If not, see <http://www.gnu.org/licenses/>.
 */

#include <cstring>
#include <cassert>
#include "ArrayManager.hpp"
ArrayManager::ArrayManager() :
    arrayStore(new StaticStore<cphvb_array>(4096*10)) {}

cphvb_array* ArrayManager::create(cphvb_array* base,
                                  cphvb_type type,
                                  cphvb_intp ndim,
                                  cphvb_index start,
                                  cphvb_index shape[CPHVB_MAXDIM],
                                  cphvb_index stride[CPHVB_MAXDIM],
                                  cphvb_intp has_init_value,
                                  cphvb_constant init_value)
{
    cphvb_array* array = arrayStore->c_next();
    array->owner          = CPHVB_PARENT;
    array->base           = base;
    array->type           = type;
    array->ndim           = ndim;
    array->start          = start;
    array->has_init_value = has_init_value;
    array->init_value     = init_value;
    array->data           = NULL;
    array->ref_count      = 1;
    std::memcpy(array->shape, shape, ndim * sizeof(cphvb_index));
    std::memcpy(array->stride, stride, ndim * sizeof(cphvb_index));

    if(array->base != NULL)
    {
        assert(array->base->base == NULL);
        assert(!has_init_value);
        ++array->base->ref_count;
        array->data = array->base->data;
    }
    return array;
}

ArrayManager::~ArrayManager()
{
    delete arrayStore;
}

void ArrayManager::erasePending(cphvb_array* array)
{
    eraseQueue.push_back(array);
}

void ArrayManager::changeOwnerPending(cphvb_array* base,
                                      cphvb_comp owner)
{
    assert(base->base == NULL);
#ifdef _WIN32
	OwnerTicket t;
	t.array = base;
	t.owner = owner;
    ownerChangeQueue.push_back(t);
#else
    ownerChangeQueue.push_back((OwnerTicket){base,owner});
#endif
}

void ArrayManager::flush()
{
    std::pair<BaseToViewMMap::iterator,BaseToViewMMap::iterator> range;
    BaseToViewMMap::iterator rit;
    std::deque<OwnerTicket>::iterator oit = ownerChangeQueue.begin();

    //First we change ownership for all those pending
    for (; oit != ownerChangeQueue.end(); ++oit)
    {
        (*oit).array->owner = (*oit).owner;
        if ((*oit).array->base == NULL)
        {   //if it is a base array we check to see if there are stale views
            range = staleView.equal_range((*oit).array);
            for (rit=range.first; rit!=range.second; ++rit)
            {   //If there are any we delete them
                arrayStore->erase(rit->second);
            }

            staleView.erase(range.first, range.second);
        }
    }
    // All ownerships are changed. So we clear the queue
    ownerChangeQueue.clear();

    //Then we delete arrays marked for deletion
    std::deque<cphvb_array*>::iterator eit = eraseQueue.begin();
    for (; eit != eraseQueue.end(); ++eit)
    {
        if ((*eit)->base == NULL)
        {   //We have to deallocate the base array because of the
            //triggering opcode CPHVB_DESTROY.
            cphvb_data_free((*eit));
            arrayStore->erase(*eit);
        }
        else if ((*eit)->base->owner == CPHVB_PARENT)
        {   //The base owner is up stream so we can delete it
            arrayStore->erase(*eit);
        }
        else
        {   //The base owner is down stream. So we postpone deletion
            staleView.insert(std::pair<cphvb_array*,
                                 cphvb_array*>((*eit)->base, *eit));
        }
    }
    // All erases have been delt with. So we clear the queue
    eraseQueue.clear();
}
<|endoftext|>


<commit_before>#include "logging.h"
#include "common/config.h"
#include "spdlog/sinks/null_sink.h"

std::shared_ptr<spdlog::logger> stderrLogger(
    const std::string& name,
    const std::string& pattern,
    const std::vector<std::string>& files,
    bool quiet) {
  std::vector<spdlog::sink_ptr> sinks;

  auto stderr_sink = spdlog::sinks::stderr_sink_mt::instance();

  if(!quiet)
    sinks.push_back(stderr_sink);

  for(auto&& file : files) {
    auto file_sink
        = std::make_shared<spdlog::sinks::simple_file_sink_st>(file, true);
    sinks.push_back(file_sink);
  }

  auto logger
      = std::make_shared<spdlog::logger>(name, begin(sinks), end(sinks));

  spdlog::register_logger(logger);
  logger->set_pattern(pattern);
  return logger;
}

bool setLoggingLevel(spdlog::logger& logger, std::string const level) {
  if(level == "trace")
    logger.set_level(spdlog::level::trace);
  else if(level == "debug")
    logger.set_level(spdlog::level::debug);
  else if(level == "info")
    logger.set_level(spdlog::level::info);
  else if(level == "err" or level == "error")
    logger.set_level(spdlog::level::err);
  else if(level == "critical")
    logger.set_level(spdlog::level::critical);
  else if(level == "off")
    logger.set_level(spdlog::level::off);
  else {
    logger.warn("Unknown log level '{}' for logger '{}'",
                level.c_str(),
                logger.name().c_str());
    return false;
  }
  return true;
}

void createLoggers(const marian::Config* options) {
  std::vector<std::string> generalLogs;
  std::vector<std::string> validLogs;

  if(options && options->has("log")) {
    generalLogs.push_back(options->get<std::string>("log"));
    validLogs.push_back(options->get<std::string>("log"));
  }

  if(options && options->has("valid-log")) {
    validLogs.push_back(options->get<std::string>("valid-log"));
  }

  // @TODO: remove unused loggers
  bool quiet = options && options->get<bool>("quiet");
  Logger general{stderrLogger("general", "[%Y-%m-%d %T] %v", generalLogs, quiet)};
  Logger valid{
      stderrLogger("valid", "[%Y-%m-%d %T] [valid] %v", validLogs, quiet)};

  if(options && options->has("log-level")) {
    std::string loglevel = options->get<std::string>("log-level");
    if(!setLoggingLevel(*general, loglevel))
      return;
    setLoggingLevel(*valid, loglevel);
  }
}
<commit_msg>Add missing log level 'warn'<commit_after>#include "logging.h"
#include "common/config.h"
#include "spdlog/sinks/null_sink.h"

std::shared_ptr<spdlog::logger> stderrLogger(
    const std::string& name,
    const std::string& pattern,
    const std::vector<std::string>& files,
    bool quiet) {
  std::vector<spdlog::sink_ptr> sinks;

  auto stderr_sink = spdlog::sinks::stderr_sink_mt::instance();

  if(!quiet)
    sinks.push_back(stderr_sink);

  for(auto&& file : files) {
    auto file_sink
        = std::make_shared<spdlog::sinks::simple_file_sink_st>(file, true);
    sinks.push_back(file_sink);
  }

  auto logger
      = std::make_shared<spdlog::logger>(name, begin(sinks), end(sinks));

  spdlog::register_logger(logger);
  logger->set_pattern(pattern);
  return logger;
}

bool setLoggingLevel(spdlog::logger& logger, std::string const level) {
  if(level == "trace")
    logger.set_level(spdlog::level::trace);
  else if(level == "debug")
    logger.set_level(spdlog::level::debug);
  else if(level == "info")
    logger.set_level(spdlog::level::info);
  else if(level == "warn")
    logger.set_level(spdlog::level::warn);
  else if(level == "err" or level == "error")
    logger.set_level(spdlog::level::err);
  else if(level == "critical")
    logger.set_level(spdlog::level::critical);
  else if(level == "off")
    logger.set_level(spdlog::level::off);
  else {
    logger.warn("Unknown log level '{}' for logger '{}'",
                level.c_str(),
                logger.name().c_str());
    return false;
  }
  return true;
}

void createLoggers(const marian::Config* options) {
  std::vector<std::string> generalLogs;
  std::vector<std::string> validLogs;

  if(options && options->has("log")) {
    generalLogs.push_back(options->get<std::string>("log"));
    validLogs.push_back(options->get<std::string>("log"));
  }

  if(options && options->has("valid-log")) {
    validLogs.push_back(options->get<std::string>("valid-log"));
  }

  // @TODO: remove unused loggers
  bool quiet = options && options->get<bool>("quiet");
  Logger general{stderrLogger("general", "[%Y-%m-%d %T] %v", generalLogs, quiet)};
  Logger valid{
      stderrLogger("valid", "[%Y-%m-%d %T] [valid] %v", validLogs, quiet)};

  if(options && options->has("log-level")) {
    std::string loglevel = options->get<std::string>("log-level");
    if(!setLoggingLevel(*general, loglevel))
      return;
    setLoggingLevel(*valid, loglevel);
  }
}
<|endoftext|>


<commit_before>#include <stdexcept>
#include <random>
#include "maybe.h"

unsigned int Maybe::maybes = 0;

Maybe::Maybe()
  :truth{0.5} {
  maybetrue = this->maybe();
}

Maybe::Maybe(float truthp){
  if (truthp <= 0.0 || truthp >= 1.0) {
    throw std::invalid_argument("A maybe object must have a truth percentage between 0.0 and 1.0");
  }
  truth = truthp;
  maybetrue = this->maybe();
}

bool Maybe::maybe(){
  maybes++;
  bool tof{false};
  float n{randomizer()};

  if (n < truth) {
    tof = true;
  }

  return tof;
}

bool Maybe::is_true(){
  return maybetrue;
}

bool Maybe::is_false(){
  return ( maybetrue == false) ;
}

int Maybe::uncertain(){
  return maybes;
}

void Maybe::update() {
  maybetrue = this->maybe();
}

void Maybe::update(float truthp) {
  if (truthp <= 0.0 || truthp >= 1.0) {
    throw std::invalid_argument("A maybe object must have a truth percentage between(or equal to) 0.0 and 1.0");
  }
  truth = truthp;
  maybetrue = this->maybe();
}

float Maybe::randomizer() {
  std::default_random_engine generator;
  std::uniform_real_distribution<float> distribution(0.0,1.0);
  float n = distribution(generator);
  while (n == truth)
  {
	n = distribution(generator);
  }

    return n;
}
<commit_msg>Maybe updated Maybe::is_false()<commit_after>#include <stdexcept>
#include <random>
#include "maybe.h"

unsigned int Maybe::maybes = 0;

Maybe::Maybe()
  :truth{0.5} {
  maybetrue = this->maybe();
}

Maybe::Maybe(float truthp){
  if (truthp <= 0.0 || truthp >= 1.0) {
    throw std::invalid_argument("A maybe object must have a truth percentage between 0.0 and 1.0");
  }
  truth = truthp;
  maybetrue = this->maybe();
}

bool Maybe::maybe(){
  maybes++;
  bool tof{false};
  float n{randomizer()};

  if (n < truth) {
    tof = true;
  }

  return tof;
}

bool Maybe::is_true(){
  return maybetrue;
}

bool Maybe::is_false(){
  return !maybetrue ;
}

int Maybe::uncertain(){
  return maybes;
}

void Maybe::update() {
  maybetrue = this->maybe();
}

void Maybe::update(float truthp) {
  if (truthp <= 0.0 || truthp >= 1.0) {
    throw std::invalid_argument("A maybe object must have a truth percentage between(or equal to) 0.0 and 1.0");
  }
  truth = truthp;
  maybetrue = this->maybe();
}

float Maybe::randomizer() {
  std::default_random_engine generator;
  std::uniform_real_distribution<float> distribution(0.0,1.0);
  float n = distribution(generator);
  while (n == truth)
  {
	n = distribution(generator);
  }

    return n;
}
<|endoftext|>


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

#define _CRT_SECURE_NO_WARNINGS
#include <stdarg.h>
#include <stdio.h>
#include "binaryninjaapi.h"

using namespace BinaryNinja;
using namespace std;

void LogListener::LogMessageCallback(void* ctxt, BNLogLevel level, const char* msg)
{
	LogListener* listener = (LogListener*)ctxt;
	listener->LogMessage(level, msg);
}

void LogListener::CloseLogCallback(void* ctxt)
{
	LogListener* listener = (LogListener*)ctxt;
	listener->CloseLog();
}

BNLogLevel LogListener::GetLogLevelCallback(void* ctxt)
{
	LogListener* listener = (LogListener*)ctxt;
	return listener->GetLogLevel();
}

void LogListener::RegisterLogListener(LogListener* listener)
{
	BNLogListener callbacks;
	callbacks.context = listener;
	callbacks.log = LogMessageCallback;
	callbacks.close = CloseLogCallback;
	callbacks.getLogLevel = GetLogLevelCallback;
	BNRegisterLogListener(&callbacks);
}

void LogListener::UnregisterLogListener(LogListener* listener)
{
	BNLogListener callbacks;
	callbacks.context = listener;
	callbacks.log = LogMessageCallback;
	callbacks.close = CloseLogCallback;
	BNUnregisterLogListener(&callbacks);
}

void LogListener::UpdateLogListeners()
{
	BNUpdateLogListeners();
}

static void PerformLog(BNLogLevel level, const char* fmt, va_list args)
{
#if defined(_MSC_VER)
	int len = _vscprintf(fmt, args);
	if (len < 0)
		return;
	char* msg = (char*)malloc(len + 1);
	if (!msg)
		return;
	if (vsnprintf(msg, len + 1, fmt, args) >= 0)
		BNLog(level, "%s", msg);
	free(msg);
#else
	char* msg;
	if (vasprintf(&msg, fmt, args) < 0)
		return;
	BNLog(level, "%s", msg);
	free(msg);
#endif
}

void BinaryNinja::Log(BNLogLevel level, const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(level, fmt, args);
}

void BinaryNinja::LogDebug(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(DebugLog, fmt, args);
}

void BinaryNinja::LogInfo(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(InfoLog, fmt, args);
}

void BinaryNinja::LogWarn(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(WarningLog, fmt, args);
}

void BinaryNinja::LogError(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(ErrorLog, fmt, args);
}

void BinaryNinja::LogAlert(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(AlertLog, fmt, args);
}

void BinaryNinja::LogToStdout(BNLogLevel minimumLevel)
{
	BNLogToStdout(minimumLevel);
}

void BinaryNinja::LogToStderr(BNLogLevel minimumLevel)
{
	BNLogToStderr(minimumLevel);
}

bool BinaryNinja::LogToFile(BNLogLevel minimumLevel, const string& path, bool append)
{
	return BNLogToFile(minimumLevel, path.c_str(), append);
}

void BinaryNinja::CloseLogs()
{
	BNCloseLogs();
}
<commit_msg>Log cleanup.<commit_after>// Copyright (c) 2015-2017 Vector 35 LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#define _CRT_SECURE_NO_WARNINGS
#include <stdarg.h>
#include <stdio.h>
#include "binaryninjaapi.h"

using namespace BinaryNinja;
using namespace std;

void LogListener::LogMessageCallback(void* ctxt, BNLogLevel level, const char* msg)
{
	LogListener* listener = (LogListener*)ctxt;
	listener->LogMessage(level, msg);
}

void LogListener::CloseLogCallback(void* ctxt)
{
	LogListener* listener = (LogListener*)ctxt;
	listener->CloseLog();
}

BNLogLevel LogListener::GetLogLevelCallback(void* ctxt)
{
	LogListener* listener = (LogListener*)ctxt;
	return listener->GetLogLevel();
}

void LogListener::RegisterLogListener(LogListener* listener)
{
	BNLogListener callbacks;
	callbacks.context = listener;
	callbacks.log = LogMessageCallback;
	callbacks.close = CloseLogCallback;
	callbacks.getLogLevel = GetLogLevelCallback;
	BNRegisterLogListener(&callbacks);
}

void LogListener::UnregisterLogListener(LogListener* listener)
{
	BNLogListener callbacks;
	callbacks.context = listener;
	callbacks.log = LogMessageCallback;
	callbacks.close = CloseLogCallback;
	BNUnregisterLogListener(&callbacks);
}

void LogListener::UpdateLogListeners()
{
	BNUpdateLogListeners();
}

static void PerformLog(BNLogLevel level, const char* fmt, va_list args)
{
#if defined(_MSC_VER)
	int len = _vscprintf(fmt, args);
	if (len < 0)
		return;
	char* msg = (char*)malloc(len + 1);
	if (!msg)
		return;
	if (vsnprintf(msg, len + 1, fmt, args) >= 0)
		BNLog(level, "%s", msg);
	free(msg);
#else
	char* msg;
	if (vasprintf(&msg, fmt, args) < 0)
		return;
	BNLog(level, "%s", msg);
	free(msg);
#endif
}

void BinaryNinja::Log(BNLogLevel level, const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(level, fmt, args);
	va_end(args);
}

void BinaryNinja::LogDebug(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(DebugLog, fmt, args);
	va_end(args);
}

void BinaryNinja::LogInfo(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(InfoLog, fmt, args);
	va_end(args);
}

void BinaryNinja::LogWarn(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(WarningLog, fmt, args);
	va_end(args);
}

void BinaryNinja::LogError(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(ErrorLog, fmt, args);
	va_end(args);
}

void BinaryNinja::LogAlert(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	PerformLog(AlertLog, fmt, args);
	va_end(args);
}

void BinaryNinja::LogToStdout(BNLogLevel minimumLevel)
{
	BNLogToStdout(minimumLevel);
}

void BinaryNinja::LogToStderr(BNLogLevel minimumLevel)
{
	BNLogToStderr(minimumLevel);
}

bool BinaryNinja::LogToFile(BNLogLevel minimumLevel, const string& path, bool append)
{
	return BNLogToFile(minimumLevel, path.c_str(), append);
}

void BinaryNinja::CloseLogs()
{
	BNCloseLogs();
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTIFFReader.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/

#include "vtkTIFFReader.h"
#include "vtkByteSwap.h"
#include <stdio.h>

void vtkTIFFReader::Swap2(short *stmp)
{
  if (this->SwapBytes)
    {
    vtkByteSwap::SwapVoidRange(stmp, 1, 2);
    }
}
void vtkTIFFReader::Swap4(long *stmp)
{
  if (this->SwapBytes)
    {
    vtkByteSwap::SwapVoidRange(stmp, 1, 4);
    }
}

void vtkTIFFReader::ReadTag(_vtkTifTag *tag, FILE *fp)
{
  short stmp;
  long ltmp;

  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  tag->TagId = stmp;

  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  tag->DataType = stmp;

  fread(&ltmp,sizeof(long),1,fp);
  this->Swap4(&ltmp);
  tag->DataCount = ltmp;

  fread(&ltmp,sizeof(long),1,fp);
  this->Swap4(&ltmp);
  tag->DataOffset = ltmp;
}

long vtkTIFFReader::ReadTagLong(_vtkTifTag *tag, FILE *fp)
{
  long result;
  long curPos;

  // if the tag is an offset just return the first value
  if (((tag->DataCount > 1)&&(tag->DataType == 4))||
      ((tag->DataCount > 2)&&(tag->DataType == 3))||
      ((tag->DataCount > 4)&&(tag->DataType == 1)))
    {
    // jump to offset and read the first value
    curPos = ftell(fp);
    fseek(fp, tag->DataOffset, SEEK_SET);
    fread(&result,sizeof(long),1,fp);
    this->Swap4(&result);
    switch (tag->DataType)
      {
      case 1: result = *((unsigned char *)&(result)); break;
      case 3: result = *((short *)&(result)); break;
      case 4: result = (long)(result); break;
      default: vtkGenericWarningMacro("Bad data in tag!");
      }
    fseek(fp, curPos, SEEK_SET);
    }
  else
    {
    switch (tag->DataType)
      {
      case 1: result = *((unsigned char *)&(tag->DataOffset)); break;
      case 3: result = *((short *)&(tag->DataOffset)); break;
      case 4: result = (long)(tag->DataOffset); break;
      default: vtkGenericWarningMacro("Bad data in tag!");
      }
    }

  return result;
}

void vtkTIFFReader::UpdateImageInformation()
{
  int xsize, ysize;
  FILE *fp;
  char lFileName[1024];
  short stmp;
  long IFDOffset;
  _vtkTifTag aTag;
  int i;
  short numTags;
  long ltmp;
  int numComp, bpp;

  // if the user has not set the extent, but has set the VOI
  // set the zaxis extent to the VOI z axis
  if (this->DataExtent[4]==0 && this->DataExtent[5] == 0 &&
      (this->DataVOI[4] || this->DataVOI[5]))
    {
    this->DataExtent[4] = this->DataVOI[4];
    this->DataExtent[5] = this->DataVOI[5];
    }

  // Allocate the space for the filename
  if (this->FileName)
    {
    sprintf(lFileName,"%s",this->FileName);
    }
  else
    {
    if (this->FilePrefix)
      {
      sprintf (lFileName, this->FilePattern,
	       this->FilePrefix, this->DataExtent[4]);
      }
    else
      {
      sprintf (lFileName, this->FilePattern,
	       this->DataExtent[4]);
      }
    }

  // get the magic number by reading in a file
  fp = fopen(lFileName,"rb");
  if (!fp)
    {
    vtkErrorMacro("Unable to open file " << lFileName);
    return;
    }

  // compare magic number to determine file type
  stmp = fgetc(fp);
  if ((fgetc(fp) != stmp)||((stmp != 'I')&&(stmp != 'M')))
    {
    vtkErrorMacro(<<"Unknown file type! Not a TIFF file!");
    fclose(fp);
    return;
    }

  // what is the byte order
  if (stmp == 'I')
    {
    this->SetDataByteOrderToLittleEndian();
    }
  else
    {
    this->SetDataByteOrderToBigEndian();
    }
  // default is upper left
  this->FileLowerLeft = 0;

  // check the version word
  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  if (stmp != 42)
    {
    vtkErrorMacro(<<"Unknown file type! Not a TIFF file!");
    fclose(fp);
    return;
    }

  // get the offset to the image file directory
  fread(&IFDOffset,sizeof(long),1,fp);
  this->Swap4(&IFDOffset);

  // now we need to read the IFD to get the additional info we need
  // seek to the first IFD
  fseek(fp, IFDOffset, SEEK_SET);

  // how many tags are there
  fread(&numTags,sizeof(short),1,fp);
  this->Swap2(&numTags);
  vtkDebugMacro("The IFD contains " << numTags << " tags.");

  // read the tags and act on it  NOTE: we could handle the Xresolution and Yresolution
  // tags and put them into the spacing ivar, but they are almost always 1.0 so
  // for now I'll skip it.
  for (i = 0; i < numTags; i++)
    {
    ReadTag(&aTag,fp);
    switch (aTag.TagId)
      {
      case 256:
	xsize = this->ReadTagLong(&aTag,fp);
	break;
      case 257:
	ysize = this->ReadTagLong(&aTag,fp);
	break;
      case 258:
	bpp = (int)this->ReadTagLong(&aTag,fp);
	if ((bpp != 8)&&(bpp != 16))
	  {
	  vtkWarningMacro(" vtkTIFFReader only supports 8 and 16 bits per sample!");
	  }
	break;
      case 259:
	ltmp = this->ReadTagLong(&aTag,fp);
	if ((ltmp != 1)&&(ltmp != 32771))
	  {
	  vtkWarningMacro(" vtkTIFFReader does not support compressed TIFF images!");
	  }
	break;
      case 273:
	ltmp = this->ReadTagLong(&aTag,fp);
	this->SetHeaderSize(ltmp);
	break;
      case 274:
	// is corner in upper left or lower left, the default is upper left
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp == 4)
	  {
	  this->FileLowerLeft = 1;
	  }
	break;
      case 277:
	numComp = (int)this->ReadTagLong(&aTag,fp);
	break;
      case 278:
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp != ysize)
	  {
	  vtkWarningMacro(" vtkTIFFReader only supports one strip!");
	  }
	break;
      case 284:
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp != 1)
	  {
	  vtkWarningMacro(" vtkTIFFReader requires planar contiguous images!");
	  }
	break;
      }
    }

  // if the user has set the VOI, just make sure its valid
  if (this->DataVOI[0] || this->DataVOI[1] ||
      this->DataVOI[2] || this->DataVOI[3] ||
      this->DataVOI[4] || this->DataVOI[5])
    {
    if ((this->DataVOI[0] < 0) ||
	(this->DataVOI[1] >= xsize) ||
	(this->DataVOI[2] < 0) ||
	(this->DataVOI[3] >= ysize))
      {
      vtkWarningMacro("The requested VOI is larger than the file's (" << lFileName << ") extent ");
      this->DataVOI[0] = 0;
      this->DataVOI[1] = xsize - 1;
      this->DataVOI[2] = 0;
      this->DataVOI[3] = ysize - 1;
      }
    }

  this->DataExtent[0] = 0;
  this->DataExtent[1] = xsize - 1;
  this->DataExtent[2] = 0;
  this->DataExtent[3] = ysize - 1;

  if (bpp == 8)
    {
    this->SetDataScalarTypeToUnsignedChar();
    }
  else
    {
    this->SetDataScalarTypeToUnsignedShort();
    }

  this->SetNumberOfScalarComponents(numComp);

  vtkImageReader::UpdateImageInformation();
}

<commit_msg>pc fixes to byte swapping<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTIFFReader.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/

#include "vtkTIFFReader.h"
#include "vtkByteSwap.h"
#include <stdio.h>

void vtkTIFFReader::Swap2(short *stmp)
{
  if (this->SwapBytes)
    {
    vtkByteSwap::SwapVoidRange(stmp, 1, 2);
    }
}
void vtkTIFFReader::Swap4(long *stmp)
{
  if (this->SwapBytes)
    {
    vtkByteSwap::SwapVoidRange(stmp, 1, 4);
    }
}

void vtkTIFFReader::ReadTag(_vtkTifTag *tag, FILE *fp)
{
  short stmp;
  long ltmp;

  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  tag->TagId = stmp;

  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  tag->DataType = stmp;

  fread(&ltmp,sizeof(long),1,fp);
  this->Swap4(&ltmp);
  tag->DataCount = ltmp;

  fread(&ltmp,sizeof(long),1,fp);
  tag->DataOffset = ltmp;
}

long vtkTIFFReader::ReadTagLong(_vtkTifTag *tag, FILE *fp)
{
  long result;
  long curPos;

  // if the tag is an offset just return the first value
  if (((tag->DataCount > 1)&&(tag->DataType == 4))||
      ((tag->DataCount > 2)&&(tag->DataType == 3))||
      ((tag->DataCount > 4)&&(tag->DataType == 1)))
    {
    // jump to offset and read the first value
    curPos = ftell(fp);
    // swap offset as 4 byte
    this->Swap4(&tag->DataOffset);
    fseek(fp, tag->DataOffset, SEEK_SET);
    fread(&result,sizeof(long),1,fp);
    switch (tag->DataType)
      {
      case 1: result = *((unsigned char *)&(result)); break;
      case 3:
	this->Swap2((short *)(&result));
	result = *((short *)&(result));
	break;
      case 4:
	this->Swap4(&result);
        result = (long)(result);
	break;
      default: vtkGenericWarningMacro("Bad data in tag!");
      }
    fseek(fp, curPos, SEEK_SET);
    }
  else
    {
    result = tag->DataOffset;
    switch (tag->DataType)
      {
      case 1: result = *((unsigned char *)&(result)); break;
      case 3:
	this->Swap2((short *)(&result));
	result = *((short *)&(result));
	break;
      case 4:
	this->Swap4(&result);
        result = (long)(result);
	break;
      default: vtkGenericWarningMacro("Bad data in tag!");
      }
    }

  return result;
}

void vtkTIFFReader::UpdateImageInformation()
{
  int xsize, ysize;
  FILE *fp;
  char lFileName[1024];
  short stmp;
  long IFDOffset;
  _vtkTifTag aTag;
  int i;
  short numTags;
  long ltmp;
  int numComp, bpp;

  // if the user has not set the extent, but has set the VOI
  // set the zaxis extent to the VOI z axis
  if (this->DataExtent[4]==0 && this->DataExtent[5] == 0 &&
      (this->DataVOI[4] || this->DataVOI[5]))
    {
    this->DataExtent[4] = this->DataVOI[4];
    this->DataExtent[5] = this->DataVOI[5];
    }

  // Allocate the space for the filename
  if (this->FileName)
    {
    sprintf(lFileName,"%s",this->FileName);
    }
  else
    {
    if (this->FilePrefix)
      {
      sprintf (lFileName, this->FilePattern,
	       this->FilePrefix, this->DataExtent[4]);
      }
    else
      {
      sprintf (lFileName, this->FilePattern,
	       this->DataExtent[4]);
      }
    }

  // get the magic number by reading in a file
  fp = fopen(lFileName,"rb");
  if (!fp)
    {
    vtkErrorMacro("Unable to open file " << lFileName);
    return;
    }

  // compare magic number to determine file type
  stmp = fgetc(fp);
  if ((fgetc(fp) != stmp)||((stmp != 'I')&&(stmp != 'M')))
    {
    vtkErrorMacro(<<"Unknown file type! Not a TIFF file!");
    fclose(fp);
    return;
    }

  // what is the byte order
  if (stmp == 'I')
    {
    this->SetDataByteOrderToLittleEndian();
    }
  else
    {
    this->SetDataByteOrderToBigEndian();
    }
  // default is upper left
  this->FileLowerLeft = 0;

  // check the version word
  fread(&stmp,sizeof(short),1,fp);
  this->Swap2(&stmp);
  if (stmp != 42)
    {
    vtkErrorMacro(<<"Unknown file type! Not a TIFF file!");
    fclose(fp);
    return;
    }

  // get the offset to the image file directory
  fread(&IFDOffset,sizeof(long),1,fp);
  this->Swap4(&IFDOffset);

  // now we need to read the IFD to get the additional info we need
  // seek to the first IFD
  fseek(fp, IFDOffset, SEEK_SET);

  // how many tags are there
  fread(&numTags,sizeof(short),1,fp);
  this->Swap2(&numTags);
  vtkDebugMacro("The IFD contains " << numTags << " tags.");

  // read the tags and act on it  NOTE: we could handle the Xresolution and Yresolution
  // tags and put them into the spacing ivar, but they are almost always 1.0 so
  // for now I'll skip it.
  for (i = 0; i < numTags; i++)
    {
    ReadTag(&aTag,fp);
    switch (aTag.TagId)
      {
      case 256:
	xsize = this->ReadTagLong(&aTag,fp);
	break;
      case 257:
	ysize = this->ReadTagLong(&aTag,fp);
	break;
      case 258:
	bpp = (int)this->ReadTagLong(&aTag,fp);
	if ((bpp != 8)&&(bpp != 16))
	  {
	  vtkWarningMacro(" vtkTIFFReader only supports 8 and 16 bits per sample!");
	  }
	break;
      case 259:
	ltmp = this->ReadTagLong(&aTag,fp);
	if ((ltmp != 1)&&(ltmp != 32771))
	  {
	  vtkWarningMacro(" vtkTIFFReader does not support compressed TIFF images!");
	  }
	break;
      case 273:
	ltmp = this->ReadTagLong(&aTag,fp);
	this->SetHeaderSize(ltmp);
	break;
      case 274:
	// is corner in upper left or lower left, the default is upper left
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp == 4)
	  {
	  this->FileLowerLeft = 1;
	  }
	break;
      case 277:
	numComp = (int)this->ReadTagLong(&aTag,fp);
	break;
      case 278:
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp != ysize)
	  {
	  vtkWarningMacro(" vtkTIFFReader only supports one strip!");
	  }
	break;
      case 284:
	ltmp = this->ReadTagLong(&aTag,fp);
	if (ltmp != 1)
	  {
	  vtkWarningMacro(" vtkTIFFReader requires planar contiguous images!");
	  }
	break;
      }
    }

  // if the user has set the VOI, just make sure its valid
  if (this->DataVOI[0] || this->DataVOI[1] ||
      this->DataVOI[2] || this->DataVOI[3] ||
      this->DataVOI[4] || this->DataVOI[5])
    {
    if ((this->DataVOI[0] < 0) ||
	(this->DataVOI[1] >= xsize) ||
	(this->DataVOI[2] < 0) ||
	(this->DataVOI[3] >= ysize))
      {
      vtkWarningMacro("The requested VOI is larger than the file's (" << lFileName << ") extent ");
      this->DataVOI[0] = 0;
      this->DataVOI[1] = xsize - 1;
      this->DataVOI[2] = 0;
      this->DataVOI[3] = ysize - 1;
      }
    }

  this->DataExtent[0] = 0;
  this->DataExtent[1] = xsize - 1;
  this->DataExtent[2] = 0;
  this->DataExtent[3] = ysize - 1;

  if (bpp == 8)
    {
    this->SetDataScalarTypeToUnsignedChar();
    }
  else
    {
    this->SetDataScalarTypeToUnsignedShort();
    }

  this->SetNumberOfScalarComponents(numComp);

  vtkImageReader::UpdateImageInformation();
}

<|endoftext|>


<commit_before>/*
    Copyright (c) 2007-2011 iMatix Corporation
    Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file

    This file is part of 0MQ.

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

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

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

#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#include "zmq.h"

#include <cassert>
#include <cstring>
#include <exception>
#include <mutex>
#include <string>
#include <iostream>

#include <thread>
#include <set>
#include "jml/utils/exc_assert.h"

namespace zmq
{

    typedef zmq_free_fn free_fn;
    typedef zmq_pollitem_t pollitem_t;

    class socket_t;

    class error_t : public std::exception
    {
    public:

        error_t () : errnum (zmq_errno ()) {}

        virtual const char *what () const throw ()
        {
            return zmq_strerror (errnum);
        }

        int num () const
        {
            return errnum;
        }

    private:

        int errnum;
    };

    inline int poll (zmq_pollitem_t *items_, int nitems_, long timeout_ = -1)
    {
        int rc = zmq_poll (items_, nitems_, timeout_);
        if (rc < 0)
            throw error_t ();
        return rc;
    }

    inline void device (int device_, void * insocket_, void* outsocket_)
    {
        int rc = zmq_device (device_, insocket_, outsocket_);
        if (rc != 0)
            throw error_t ();
    }

    class message_t : private zmq_msg_t
    {
        friend class socket_t;

    public:

        inline message_t ()
        {
            int rc = zmq_msg_init (this);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (size_t size_)
        {
            int rc = zmq_msg_init_size (this, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (const std::string & s)
        {
            int rc = zmq_msg_init_size (this, s.size());
            if (rc != 0)
                throw error_t ();
            std::copy(s.begin(), s.end(), (char *)data());
        }

        inline message_t (const message_t & other) noexcept
        {
            int rc = zmq_msg_init (this);
            if (rc == 0)
                rc = zmq_msg_copy(this, const_cast<message_t *>(&other));
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (message_t && other) noexcept
        {
            int rc = zmq_msg_init (this);
            if (rc == 0)
                rc = zmq_msg_move(this, &other);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t & operator = (const message_t & other) noexcept
        {
            int rc = zmq_msg_copy(this, const_cast<message_t *>(&other));
            if (rc != 0)
                throw error_t ();
            return *this;
        }

        inline message_t & operator = (message_t && other) noexcept
        {
            int rc = zmq_msg_move(this, &other);
            if (rc != 0)
                throw error_t ();
            return *this;
        }

        inline ~message_t ()
        {
            int rc = zmq_msg_close (this);
            assert (rc == 0);
            (void)rc;
        }

        inline void rebuild ()
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init (this);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (size_t size_)
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_size (this, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline void move (message_t *msg_)
        {
            int rc = zmq_msg_move (this, (zmq_msg_t*) msg_);
            if (rc != 0)
                throw error_t ();
        }

        inline void copy (message_t *msg_)
        {
            int rc = zmq_msg_copy (this, (zmq_msg_t*) msg_);
            if (rc != 0)
                throw error_t ();
        }

        inline char *data ()
        {
            return (char *)zmq_msg_data (this);
        }

        inline const char *data () const
        {
            return (const char *)zmq_msg_data (const_cast<message_t *>(this));
        }

        inline size_t size () const
        {
            return zmq_msg_size (const_cast<message_t *>(this));
        }

        std::string toString() const
        {
            return std::string(data(), data() + size());
        }

    private:

        //  Disable implicit message copying, so that users won't use shared
        //  messages (less efficient) without being aware of the fact.
        //message_t (const message_t&);
        //void operator = (const message_t&);
    };

    class context_t
    {
        friend class socket_t;

    public:

        inline context_t (int io_threads_)
        {
            ptr = zmq_init (io_threads_);
            if (ptr == NULL)
                throw error_t ();
        }

        inline ~context_t ()
        {
            // If this throws, it means that you forgot to destroy a zmq_socket_t object
            // created with this context before you closed the context.
            ExcAssertEqual(sockets.size(), 0);

            int rc = zmq_term (ptr);
            assert (rc == 0);
            (void)rc;
        }

        //  Be careful with this, it's probably only useful for
        //  using the C api together with an existing C++ api.
        //  Normally you should never need to use this.
        inline operator void* ()
        {
            return ptr;
        }

        void registerSocket(socket_t * sock)
        {
            std::unique_lock<std::mutex> guard(lock);
            ExcAssertEqual(sockets.count(sock), 0);
            sockets.insert(sock);
        }

        void unregisterSocket(socket_t * sock)
        {
            std::unique_lock<std::mutex> guard(lock);
            ExcAssertEqual(sockets.count(sock), 1);
            sockets.erase(sock);
        }

    private:

        void *ptr;

        context_t (const context_t&);
        void operator = (const context_t&);

        std::mutex lock;
        std::set<socket_t *> sockets;
    };

    class socket_t
    {
    public:
        context_t * context_;

        inline socket_t (context_t &context_, int type_)
            : context_(&context_)
        {
            ptr = zmq_socket (context_.ptr, type_);
            if (ptr == NULL)
                throw error_t ();

            context_.registerSocket(this);
        }

        inline ~socket_t ()
        {
            int linger = 0;
            setsockopt (ZMQ_LINGER, &linger, sizeof(linger));
            int rc = zmq_close (ptr);
            assert (rc == 0);
            (void)rc;

            context_->unregisterSocket(this);
        }

        inline operator void* ()
        {
            return ptr;
        }

        inline void setsockopt (int option_, const void *optval_,
            size_t optvallen_)
        {
            int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void getsockopt (int option_, void *optval_,
            size_t *optvallen_)
        {
            int rc = zmq_getsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void bind (const std::string & addr_)
        {
            int rc = zmq_bind (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline void unbind (const std::string & addr_)
        {
            int rc = zmq_unbind (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline int tryUnbind (const std::string & addr_)
        {
            int rc = zmq_unbind (ptr, addr_.c_str());
            return rc;
        }

        inline void connect (const std::string & addr_)
        {
            int rc = zmq_connect (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline void disconnect (const std::string & addr_)
        {
            int rc = zmq_disconnect (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline int tryDisconnect (const std::string & addr_)
        {
            return zmq_disconnect (ptr, addr_.c_str());
        }

        inline bool send (message_t &msg_, int flags_ = 0)
        {
            int rc = zmq_sendmsg (ptr, &msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline bool send (message_t && msg_, int flags_ = 0)
        {
            int rc = zmq_sendmsg (ptr, &msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline bool recv (message_t *msg_, int flags_ = 0)
        {
            int rc = zmq_recvmsg (ptr, msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

    private:

        void *ptr;

        socket_t (const socket_t&);
        socket_t (socket_t&&);
        void operator = (const socket_t&);
        void operator = (socket_t&&);
    };

}

#endif
<commit_msg>make zmq_msg_t a public base of zmq::message_t to allow base functions to be called<commit_after>/*
    Copyright (c) 2007-2011 iMatix Corporation
    Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file

    This file is part of 0MQ.

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

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

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

#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#include "zmq.h"

#include <cassert>
#include <cstring>
#include <exception>
#include <mutex>
#include <string>
#include <iostream>

#include <thread>
#include <set>
#include "jml/utils/exc_assert.h"

namespace zmq
{

    typedef zmq_free_fn free_fn;
    typedef zmq_pollitem_t pollitem_t;

    class socket_t;

    class error_t : public std::exception
    {
    public:

        error_t () : errnum (zmq_errno ()) {}

        virtual const char *what () const throw ()
        {
            return zmq_strerror (errnum);
        }

        int num () const
        {
            return errnum;
        }

    private:

        int errnum;
    };

    inline int poll (zmq_pollitem_t *items_, int nitems_, long timeout_ = -1)
    {
        int rc = zmq_poll (items_, nitems_, timeout_);
        if (rc < 0)
            throw error_t ();
        return rc;
    }

    inline void device (int device_, void * insocket_, void* outsocket_)
    {
        int rc = zmq_device (device_, insocket_, outsocket_);
        if (rc != 0)
            throw error_t ();
    }

    class message_t : public zmq_msg_t
    {
        friend class socket_t;

    public:

        inline message_t ()
        {
            int rc = zmq_msg_init (this);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (size_t size_)
        {
            int rc = zmq_msg_init_size (this, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (const std::string & s)
        {
            int rc = zmq_msg_init_size (this, s.size());
            if (rc != 0)
                throw error_t ();
            std::copy(s.begin(), s.end(), (char *)data());
        }

        inline message_t (const message_t & other) noexcept
        {
            int rc = zmq_msg_init (this);
            if (rc == 0)
                rc = zmq_msg_copy(this, const_cast<message_t *>(&other));
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (message_t && other) noexcept
        {
            int rc = zmq_msg_init (this);
            if (rc == 0)
                rc = zmq_msg_move(this, &other);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t & operator = (const message_t & other) noexcept
        {
            int rc = zmq_msg_copy(this, const_cast<message_t *>(&other));
            if (rc != 0)
                throw error_t ();
            return *this;
        }

        inline message_t & operator = (message_t && other) noexcept
        {
            int rc = zmq_msg_move(this, &other);
            if (rc != 0)
                throw error_t ();
            return *this;
        }

        inline ~message_t ()
        {
            int rc = zmq_msg_close (this);
            assert (rc == 0);
            (void)rc;
        }

        inline void rebuild ()
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init (this);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (size_t size_)
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_size (this, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_close (this);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_data (this, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline void move (message_t *msg_)
        {
            int rc = zmq_msg_move (this, (zmq_msg_t*) msg_);
            if (rc != 0)
                throw error_t ();
        }

        inline void copy (message_t *msg_)
        {
            int rc = zmq_msg_copy (this, (zmq_msg_t*) msg_);
            if (rc != 0)
                throw error_t ();
        }

        inline char *data ()
        {
            return (char *)zmq_msg_data (this);
        }

        inline const char *data () const
        {
            return (const char *)zmq_msg_data (const_cast<message_t *>(this));
        }

        inline size_t size () const
        {
            return zmq_msg_size (const_cast<message_t *>(this));
        }

        std::string toString() const
        {
            return std::string(data(), data() + size());
        }

    private:

        //  Disable implicit message copying, so that users won't use shared
        //  messages (less efficient) without being aware of the fact.
        //message_t (const message_t&);
        //void operator = (const message_t&);
    };

    class context_t
    {
        friend class socket_t;

    public:

        inline context_t (int io_threads_)
        {
            ptr = zmq_init (io_threads_);
            if (ptr == NULL)
                throw error_t ();
        }

        inline ~context_t ()
        {
            // If this throws, it means that you forgot to destroy a zmq_socket_t object
            // created with this context before you closed the context.
            ExcAssertEqual(sockets.size(), 0);

            int rc = zmq_term (ptr);
            assert (rc == 0);
            (void)rc;
        }

        //  Be careful with this, it's probably only useful for
        //  using the C api together with an existing C++ api.
        //  Normally you should never need to use this.
        inline operator void* ()
        {
            return ptr;
        }

        void registerSocket(socket_t * sock)
        {
            std::unique_lock<std::mutex> guard(lock);
            ExcAssertEqual(sockets.count(sock), 0);
            sockets.insert(sock);
        }

        void unregisterSocket(socket_t * sock)
        {
            std::unique_lock<std::mutex> guard(lock);
            ExcAssertEqual(sockets.count(sock), 1);
            sockets.erase(sock);
        }

    private:

        void *ptr;

        context_t (const context_t&);
        void operator = (const context_t&);

        std::mutex lock;
        std::set<socket_t *> sockets;
    };

    class socket_t
    {
    public:
        context_t * context_;

        inline socket_t (context_t &context_, int type_)
            : context_(&context_)
        {
            ptr = zmq_socket (context_.ptr, type_);
            if (ptr == NULL)
                throw error_t ();

            context_.registerSocket(this);
        }

        inline ~socket_t ()
        {
            int linger = 0;
            setsockopt (ZMQ_LINGER, &linger, sizeof(linger));
            int rc = zmq_close (ptr);
            assert (rc == 0);
            (void)rc;

            context_->unregisterSocket(this);
        }

        inline operator void* ()
        {
            return ptr;
        }

        inline void setsockopt (int option_, const void *optval_,
            size_t optvallen_)
        {
            int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void getsockopt (int option_, void *optval_,
            size_t *optvallen_)
        {
            int rc = zmq_getsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void bind (const std::string & addr_)
        {
            int rc = zmq_bind (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline void unbind (const std::string & addr_)
        {
            int rc = zmq_unbind (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline int tryUnbind (const std::string & addr_)
        {
            int rc = zmq_unbind (ptr, addr_.c_str());
            return rc;
        }

        inline void connect (const std::string & addr_)
        {
            int rc = zmq_connect (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline void disconnect (const std::string & addr_)
        {
            int rc = zmq_disconnect (ptr, addr_.c_str());
            if (rc != 0)
                throw error_t ();
        }

        inline int tryDisconnect (const std::string & addr_)
        {
            return zmq_disconnect (ptr, addr_.c_str());
        }

        inline bool send (message_t &msg_, int flags_ = 0)
        {
            int rc = zmq_sendmsg (ptr, &msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline bool send (message_t && msg_, int flags_ = 0)
        {
            int rc = zmq_sendmsg (ptr, &msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline bool recv (message_t *msg_, int flags_ = 0)
        {
            int rc = zmq_recvmsg (ptr, msg_, flags_);
            if (rc >= 0)
                return true;
            if (rc == -1 && zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

    private:

        void *ptr;

        socket_t (const socket_t&);
        socket_t (socket_t&&);
        void operator = (const socket_t&);
        void operator = (socket_t&&);
    };

}

#endif
<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "impeller/geometry/path.h"

#include <optional>

#include "impeller/geometry/path_component.h"

namespace impeller {

Path::Path() {
  AddContourComponent({});
};

Path::~Path() = default;

std::tuple<size_t, size_t> Path::Polyline::GetContourPointBounds(
    size_t contour_index) const {
  if (contour_index >= contours.size()) {
    return {points.size(), points.size()};
  }
  const size_t start_index = contours.at(contour_index).start_index;
  const size_t end_index = (contour_index >= contours.size() - 1)
                               ? points.size()
                               : contours.at(contour_index + 1).start_index;
  return std::make_tuple(start_index, end_index);
}

size_t Path::GetComponentCount() const {
  return components_.size();
}

void Path::SetFillType(FillType fill) {
  fill_ = fill;
}

FillType Path::GetFillType() const {
  return fill_;
}

Path& Path::AddLinearComponent(Point p1, Point p2) {
  linears_.emplace_back(p1, p2);
  components_.emplace_back(ComponentType::kLinear, linears_.size() - 1);
  return *this;
}

Path& Path::AddQuadraticComponent(Point p1, Point cp, Point p2) {
  quads_.emplace_back(p1, cp, p2);
  components_.emplace_back(ComponentType::kQuadratic, quads_.size() - 1);
  return *this;
}

Path& Path::AddCubicComponent(Point p1, Point cp1, Point cp2, Point p2) {
  cubics_.emplace_back(p1, cp1, cp2, p2);
  components_.emplace_back(ComponentType::kCubic, cubics_.size() - 1);
  return *this;
}

Path& Path::AddContourComponent(Point destination, bool is_closed) {
  if (components_.size() > 0 &&
      components_.back().type == ComponentType::kContour) {
    // Never insert contiguous contours.
    contours_.back() = ContourComponent(destination, is_closed);
  } else {
    contours_.emplace_back(ContourComponent(destination, is_closed));
    components_.emplace_back(ComponentType::kContour, contours_.size() - 1);
  }
  return *this;
}

void Path::SetContourClosed(bool is_closed) {
  contours_.back().is_closed = is_closed;
}

void Path::EnumerateComponents(
    const Applier<LinearPathComponent>& linear_applier,
    const Applier<QuadraticPathComponent>& quad_applier,
    const Applier<CubicPathComponent>& cubic_applier,
    const Applier<ContourComponent>& contour_applier) const {
  size_t currentIndex = 0;
  for (const auto& component : components_) {
    switch (component.type) {
      case ComponentType::kLinear:
        if (linear_applier) {
          linear_applier(currentIndex, linears_[component.index]);
        }
        break;
      case ComponentType::kQuadratic:
        if (quad_applier) {
          quad_applier(currentIndex, quads_[component.index]);
        }
        break;
      case ComponentType::kCubic:
        if (cubic_applier) {
          cubic_applier(currentIndex, cubics_[component.index]);
        }
        break;
      case ComponentType::kContour:
        if (contour_applier) {
          contour_applier(currentIndex, contours_[component.index]);
        }
        break;
    }
    currentIndex++;
  }
}

bool Path::GetLinearComponentAtIndex(size_t index,
                                     LinearPathComponent& linear) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kLinear) {
    return false;
  }

  linear = linears_[components_[index].index];
  return true;
}

bool Path::GetQuadraticComponentAtIndex(
    size_t index,
    QuadraticPathComponent& quadratic) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kQuadratic) {
    return false;
  }

  quadratic = quads_[components_[index].index];
  return true;
}

bool Path::GetCubicComponentAtIndex(size_t index,
                                    CubicPathComponent& cubic) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kCubic) {
    return false;
  }

  cubic = cubics_[components_[index].index];
  return true;
}

bool Path::GetContourComponentAtIndex(size_t index,
                                      ContourComponent& move) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kContour) {
    return false;
  }

  move = contours_[components_[index].index];
  return true;
}

bool Path::UpdateLinearComponentAtIndex(size_t index,
                                        const LinearPathComponent& linear) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kLinear) {
    return false;
  }

  linears_[components_[index].index] = linear;
  return true;
}

bool Path::UpdateQuadraticComponentAtIndex(
    size_t index,
    const QuadraticPathComponent& quadratic) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kQuadratic) {
    return false;
  }

  quads_[components_[index].index] = quadratic;
  return true;
}

bool Path::UpdateCubicComponentAtIndex(size_t index,
                                       CubicPathComponent& cubic) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kCubic) {
    return false;
  }

  cubics_[components_[index].index] = cubic;
  return true;
}

bool Path::UpdateContourComponentAtIndex(size_t index,
                                         const ContourComponent& move) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kContour) {
    return false;
  }

  contours_[components_[index].index] = move;
  return true;
}

Path::Polyline Path::CreatePolyline(
    const SmoothingApproximation& approximation) const {
  Polyline polyline;

  std::optional<Point> previous_contour_point;
  auto collect_points = [&polyline, &previous_contour_point](
                            const std::vector<Point>& collection) {
    if (collection.empty()) {
      return;
    }

    polyline.points.reserve(polyline.points.size() + collection.size());

    for (const auto& point : collection) {
      if (previous_contour_point.has_value() &&
          previous_contour_point.value() == point) {
        // Skip over duplicate points in the same contour.
        continue;
      }
      previous_contour_point = point;
      polyline.points.push_back(point);
    }
  };

  for (size_t component_i = 0; component_i < components_.size();
       component_i++) {
    const auto& component = components_[component_i];
    switch (component.type) {
      case ComponentType::kLinear:
        collect_points(linears_[component.index].CreatePolyline());
        break;
      case ComponentType::kQuadratic:
        collect_points(quads_[component.index].CreatePolyline(approximation));
        break;
      case ComponentType::kCubic:
        collect_points(cubics_[component.index].CreatePolyline(approximation));
        break;
      case ComponentType::kContour:
        if (component_i == components_.size() - 1) {
          // If the last component is a contour, that means it's an empty
          // contour, so skip it.
          continue;
        }
        const auto& contour = contours_[component.index];
        polyline.contours.push_back({.start_index = polyline.points.size(),
                                     .is_closed = contour.is_closed});
        previous_contour_point = std::nullopt;
        collect_points({contour.destination});
        break;
    }
  }
  return polyline;
}

std::optional<Rect> Path::GetBoundingBox() const {
  auto min_max = GetMinMaxCoveragePoints();
  if (!min_max.has_value()) {
    return std::nullopt;
  }
  auto min = min_max->first;
  auto max = min_max->second;
  const auto difference = max - min;
  return Rect{min.x, min.y, difference.x, difference.y};
}

std::optional<Rect> Path::GetTransformedBoundingBox(
    const Matrix& transform) const {
  auto bounds = GetBoundingBox();
  if (!bounds.has_value()) {
    return std::nullopt;
  }
  return bounds->TransformBounds(transform);
}

std::optional<std::pair<Point, Point>> Path::GetMinMaxCoveragePoints() const {
  if (linears_.empty() && quads_.empty() && cubics_.empty()) {
    return std::nullopt;
  }

  std::optional<Point> min, max;

  auto clamp = [&min, &max](const std::vector<Point>& extrema) {
    for (const auto& extremum : extrema) {
      if (!min.has_value()) {
        min = extremum;
      }

      if (!max.has_value()) {
        max = extremum;
      }

      min->x = std::min(min->x, extremum.x);
      min->y = std::min(min->y, extremum.y);
      max->x = std::max(max->x, extremum.x);
      max->y = std::max(max->y, extremum.y);
    }
  };

  for (const auto& linear : linears_) {
    clamp(linear.Extrema());
  }

  for (const auto& quad : quads_) {
    clamp(quad.Extrema());
  }

  for (const auto& cubic : cubics_) {
    clamp(cubic.Extrema());
  }

  if (!min.has_value() || !max.has_value()) {
    return std::nullopt;
  }

  return std::make_pair(min.value(), max.value());
}

}  // namespace impeller
<commit_msg>[Impeller] fix quadradic behavior in polyline creation (#36680)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "impeller/geometry/path.h"

#include <optional>

#include "impeller/geometry/path_component.h"

namespace impeller {

Path::Path() {
  AddContourComponent({});
};

Path::~Path() = default;

std::tuple<size_t, size_t> Path::Polyline::GetContourPointBounds(
    size_t contour_index) const {
  if (contour_index >= contours.size()) {
    return {points.size(), points.size()};
  }
  const size_t start_index = contours.at(contour_index).start_index;
  const size_t end_index = (contour_index >= contours.size() - 1)
                               ? points.size()
                               : contours.at(contour_index + 1).start_index;
  return std::make_tuple(start_index, end_index);
}

size_t Path::GetComponentCount() const {
  return components_.size();
}

void Path::SetFillType(FillType fill) {
  fill_ = fill;
}

FillType Path::GetFillType() const {
  return fill_;
}

Path& Path::AddLinearComponent(Point p1, Point p2) {
  linears_.emplace_back(p1, p2);
  components_.emplace_back(ComponentType::kLinear, linears_.size() - 1);
  return *this;
}

Path& Path::AddQuadraticComponent(Point p1, Point cp, Point p2) {
  quads_.emplace_back(p1, cp, p2);
  components_.emplace_back(ComponentType::kQuadratic, quads_.size() - 1);
  return *this;
}

Path& Path::AddCubicComponent(Point p1, Point cp1, Point cp2, Point p2) {
  cubics_.emplace_back(p1, cp1, cp2, p2);
  components_.emplace_back(ComponentType::kCubic, cubics_.size() - 1);
  return *this;
}

Path& Path::AddContourComponent(Point destination, bool is_closed) {
  if (components_.size() > 0 &&
      components_.back().type == ComponentType::kContour) {
    // Never insert contiguous contours.
    contours_.back() = ContourComponent(destination, is_closed);
  } else {
    contours_.emplace_back(ContourComponent(destination, is_closed));
    components_.emplace_back(ComponentType::kContour, contours_.size() - 1);
  }
  return *this;
}

void Path::SetContourClosed(bool is_closed) {
  contours_.back().is_closed = is_closed;
}

void Path::EnumerateComponents(
    const Applier<LinearPathComponent>& linear_applier,
    const Applier<QuadraticPathComponent>& quad_applier,
    const Applier<CubicPathComponent>& cubic_applier,
    const Applier<ContourComponent>& contour_applier) const {
  size_t currentIndex = 0;
  for (const auto& component : components_) {
    switch (component.type) {
      case ComponentType::kLinear:
        if (linear_applier) {
          linear_applier(currentIndex, linears_[component.index]);
        }
        break;
      case ComponentType::kQuadratic:
        if (quad_applier) {
          quad_applier(currentIndex, quads_[component.index]);
        }
        break;
      case ComponentType::kCubic:
        if (cubic_applier) {
          cubic_applier(currentIndex, cubics_[component.index]);
        }
        break;
      case ComponentType::kContour:
        if (contour_applier) {
          contour_applier(currentIndex, contours_[component.index]);
        }
        break;
    }
    currentIndex++;
  }
}

bool Path::GetLinearComponentAtIndex(size_t index,
                                     LinearPathComponent& linear) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kLinear) {
    return false;
  }

  linear = linears_[components_[index].index];
  return true;
}

bool Path::GetQuadraticComponentAtIndex(
    size_t index,
    QuadraticPathComponent& quadratic) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kQuadratic) {
    return false;
  }

  quadratic = quads_[components_[index].index];
  return true;
}

bool Path::GetCubicComponentAtIndex(size_t index,
                                    CubicPathComponent& cubic) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kCubic) {
    return false;
  }

  cubic = cubics_[components_[index].index];
  return true;
}

bool Path::GetContourComponentAtIndex(size_t index,
                                      ContourComponent& move) const {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kContour) {
    return false;
  }

  move = contours_[components_[index].index];
  return true;
}

bool Path::UpdateLinearComponentAtIndex(size_t index,
                                        const LinearPathComponent& linear) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kLinear) {
    return false;
  }

  linears_[components_[index].index] = linear;
  return true;
}

bool Path::UpdateQuadraticComponentAtIndex(
    size_t index,
    const QuadraticPathComponent& quadratic) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kQuadratic) {
    return false;
  }

  quads_[components_[index].index] = quadratic;
  return true;
}

bool Path::UpdateCubicComponentAtIndex(size_t index,
                                       CubicPathComponent& cubic) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kCubic) {
    return false;
  }

  cubics_[components_[index].index] = cubic;
  return true;
}

bool Path::UpdateContourComponentAtIndex(size_t index,
                                         const ContourComponent& move) {
  if (index >= components_.size()) {
    return false;
  }

  if (components_[index].type != ComponentType::kContour) {
    return false;
  }

  contours_[components_[index].index] = move;
  return true;
}

Path::Polyline Path::CreatePolyline(
    const SmoothingApproximation& approximation) const {
  Polyline polyline;

  std::optional<Point> previous_contour_point;
  auto collect_points = [&polyline, &previous_contour_point](
                            const std::vector<Point>& collection) {
    if (collection.empty()) {
      return;
    }

    for (const auto& point : collection) {
      if (previous_contour_point.has_value() &&
          previous_contour_point.value() == point) {
        // Skip over duplicate points in the same contour.
        continue;
      }
      previous_contour_point = point;
      polyline.points.push_back(point);
    }
  };

  for (size_t component_i = 0; component_i < components_.size();
       component_i++) {
    const auto& component = components_[component_i];
    switch (component.type) {
      case ComponentType::kLinear:
        collect_points(linears_[component.index].CreatePolyline());
        break;
      case ComponentType::kQuadratic:
        collect_points(quads_[component.index].CreatePolyline(approximation));
        break;
      case ComponentType::kCubic:
        collect_points(cubics_[component.index].CreatePolyline(approximation));
        break;
      case ComponentType::kContour:
        if (component_i == components_.size() - 1) {
          // If the last component is a contour, that means it's an empty
          // contour, so skip it.
          continue;
        }
        const auto& contour = contours_[component.index];
        polyline.contours.push_back({.start_index = polyline.points.size(),
                                     .is_closed = contour.is_closed});
        previous_contour_point = std::nullopt;
        collect_points({contour.destination});
        break;
    }
  }
  return polyline;
}

std::optional<Rect> Path::GetBoundingBox() const {
  auto min_max = GetMinMaxCoveragePoints();
  if (!min_max.has_value()) {
    return std::nullopt;
  }
  auto min = min_max->first;
  auto max = min_max->second;
  const auto difference = max - min;
  return Rect{min.x, min.y, difference.x, difference.y};
}

std::optional<Rect> Path::GetTransformedBoundingBox(
    const Matrix& transform) const {
  auto bounds = GetBoundingBox();
  if (!bounds.has_value()) {
    return std::nullopt;
  }
  return bounds->TransformBounds(transform);
}

std::optional<std::pair<Point, Point>> Path::GetMinMaxCoveragePoints() const {
  if (linears_.empty() && quads_.empty() && cubics_.empty()) {
    return std::nullopt;
  }

  std::optional<Point> min, max;

  auto clamp = [&min, &max](const std::vector<Point>& extrema) {
    for (const auto& extremum : extrema) {
      if (!min.has_value()) {
        min = extremum;
      }

      if (!max.has_value()) {
        max = extremum;
      }

      min->x = std::min(min->x, extremum.x);
      min->y = std::min(min->y, extremum.y);
      max->x = std::max(max->x, extremum.x);
      max->y = std::max(max->y, extremum.y);
    }
  };

  for (const auto& linear : linears_) {
    clamp(linear.Extrema());
  }

  for (const auto& quad : quads_) {
    clamp(quad.Extrema());
  }

  for (const auto& cubic : cubics_) {
    clamp(cubic.Extrema());
  }

  if (!min.has_value() || !max.has_value()) {
    return std::nullopt;
  }

  return std::make_pair(min.value(), max.value());
}

}  // namespace impeller
<|endoftext|>