<commit_before>/*
** Copyright 2009-2011 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 <memory>
#include <QtXml>
#include <stdlib.h>
#include <string.h>
#include "com/centreon/broker/correlation/parser.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::correlation;

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Generate automatic services dependencies.
 */
void parser::_auto_services_dependencies() {
  for (std::map<std::pair<unsigned int, unsigned int>, node>::iterator
         it = _services->begin(),
         end = _services->end();
       it != end;
       ++it) {
    std::map<unsigned int, node>::iterator it2(_hosts->find(it->first.first));
    if (it2 == _hosts->end())
      throw (exceptions::msg() << "could not find host "
               << it->first.first << " for service "
               << it->first.second);
    logging::config << logging::MEDIUM << "correlation: service "
      << it->first.second << " automatically depends on host "
      << it->first.first;
    it->second.depends_on.push_back(&(it2->second));
    it2->second.depended_by.push_back(&(it->second));
  }
  return ;
}

/**
 *  Find a node with its host_id and optionally its service_id.
 *
 *  @param[in] host_id    String of the host_id.
 *  @param[in] service_id Potentially NULL string of the service_id.
 *
 *  @return Node matching host_id/service_id.
 */
node* parser::_find_node(char const* host_id, char const* service_id) {
  node* n(NULL);
  if (!service_id) {
    std::map<unsigned int, node>::iterator it(
      _hosts->find(strtoul(host_id, NULL, 0)));
    if (it != _hosts->end())
      n = &it->second;
  }
  else {
    std::map<std::pair<unsigned int, unsigned int>, node>::iterator it(
      _services->find(std::make_pair(strtoul(host_id, NULL, 0),
        strtoul(service_id, NULL, 0))));
    if (it != _services->end())
      n = &it->second;
  }
  return (n);
}

bool parser::startElement(QString const& uri,
                          QString const& localname,
                          QString const& qname,
                          QXmlAttributes const& attrs) {
  (void)uri;
  (void)qname;
  if (!_in_root)
    _in_root = true;
  else {
    char const* value(localname.toStdString().c_str());
    if (!strcmp(value, "dependency")) {
      QString hi1;
      QString hi2;
      char* host_id1 = NULL;
      char* host_id2 = NULL;
      node* n1 = NULL;
      node* n2 = NULL;
      QString si1;
      QString si2;
      char const* service_id1 = NULL;
      char const* service_id2 = NULL;

      // Fetch attributes of the XML node.
      hi1 = attrs.value("dependent_host");
      hi2 = attrs.value("host");
      si1 = attrs.value("dependent_service");
      si2 = attrs.value("service");
      if (!hi1.size() || !hi2.size())
        throw (exceptions::msg() << "missing an host id for an " \
                 "element of a dependency definition");
      if (si1.size())
        service_id1 = si1.toStdString().c_str();
      if (si2.size())
        service_id2 = si2.toStdString().c_str();

      // Process these attributes.
      n1 = _find_node(host_id1, service_id1);
      n2 = _find_node(host_id2, service_id2);
      if (n1 && n2) {
        logging::config << logging::MEDIUM << "correlation: node ("
          << host_id1 << ", " << service_id1 << ") depends on node ("
          << host_id2 << ", " << service_id2 << ")";
        n1->depends_on.push_back(n2);
        n2->depended_by.push_back(n1);
      }
    }
    else if (!strcmp(value, "host")) {
      QString i_attr;
      node n;

      // Get XML node attribute.
      i_attr = attrs.value("id");
      if (!i_attr.size())
        throw (exceptions::msg() << "could not find an 'id' attribute" \
                 " on a 'host' definition");

      // Process attribute.
      n.host_id = strtoul(i_attr.toStdString().c_str(), NULL, 0);
      (*_hosts)[n.host_id] = n;
      logging::config << logging::MEDIUM
        << "correlation: new host " << n.host_id;
    }
    else if (!strcmp(value, "parent")) {
      QString host_attr;
      QString parent_attr;
      std::map<unsigned int, node>::iterator it1;
      std::map<unsigned int, node>::iterator it2;

      // Get XML node attributes.
      host_attr = attrs.value("host");
      parent_attr = attrs.value("parent");
      if (!host_attr.size() || !parent_attr.size())
        throw (exceptions::msg() << "could not find 'host' or " \
                 "'parent' attribute of a parenting definition");

      // Process attributes.
      it1 = (*_hosts).find(strtoul(host_attr.toStdString().c_str(),
        NULL,
        0));
      it2 = (*_hosts).find(strtoul(parent_attr.toStdString().c_str(),
        NULL,
        0));
      if ((it1 != (*_hosts).end()) && (it2 != (*_hosts).end())) {
        logging::config << logging::MEDIUM << "correlation: host "
          << it2->second.host_id << " is parent of host "
          << it1->second.host_id;
        it1->second.parents.push_back(&it2->second);
        it2->second.children.push_back(&it1->second);
      }
    }
    else if (!strcmp(value, "service")) {
      QString host_attr;
      QString id_attr;
      node n;

      // Get XML node attributes.
      host_attr = attrs.value("host");
      id_attr = attrs.value("id");
      if (!host_attr.size() || !id_attr.size())
        throw (exceptions::msg() << "could not find 'host' or 'id' " \
                 "attribute of a 'service' definition");

      // Process attributes.
      n.host_id = strtoul(host_attr.toStdString().c_str(), NULL, 0);
      n.service_id = strtoul(id_attr.toStdString().c_str(), NULL, 0);
      (*_services)[std::make_pair(n.host_id, n.service_id)] = n;
      logging::config << logging::MEDIUM
        << "correlation: new service (" << n.host_id << ", "
        << n.service_id << ")";
    }
  }
  return (true);
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
parser::parser() {}

/**
 *  Copy constructor.
 *
 *  @param[in] p Unused.
 */
parser::parser(parser const& p) : QXmlDefaultHandler() {
  (void)p;
}

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

/**
 *  Assignment operator.
 *
 *  @param[in] p Unused.
 *
 *  @return *this
 */
parser& parser::operator=(parser const& p) {
  (void)p;
  return (*this);
}

/**
 *  Parse a configuration file.
 *
 *  @param[in]  filename Path to the correlation file.
 *  @param[out] hosts    List of hosts.
 *  @param[out] services List of services.
 */
void parser::parse(QString const& filename,
                   std::map<unsigned int, node>& hosts,
                   std::map<std::pair<unsigned int, unsigned int>, node>& services) {
  QXmlSimpleReader reader;
  _hosts = &hosts;
  _services = &services;
  try {
    reader.setContentHandler(this);
    reader.setErrorHandler(this);
    QFile qf(filename);
    if (!qf.open(QIODevice::ReadOnly))
      throw (exceptions::msg() << qf.errorString());
    std::auto_ptr<QXmlInputSource> source(new QXmlInputSource(&qf));
    reader.parse(source.get());
    _auto_services_dependencies();
  }
  catch (QXmlParseException const& e) {
    logging::config << logging::HIGH << "correlation: parsing error " \
         "on \"" << filename << "\" (line "
      << (unsigned int)e.lineNumber() << ", character "
      << (unsigned int)e.columnNumber() << "): " << e.message();
  }
  catch (exceptions::msg const& e) {
    logging::config << logging::HIGH << "correlation: error while " \
      "parsing correlation file \"" << filename << "\": " << e.what();
  }
  return ;
}
<commit_msg>Bugfix in correlation file parsing.<commit_after>/*
** Copyright 2009-2011 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 <memory>
#include <QtXml>
#include <stdlib.h>
#include <string.h>
#include "com/centreon/broker/correlation/parser.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::correlation;

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Generate automatic services dependencies.
 */
void parser::_auto_services_dependencies() {
  for (std::map<std::pair<unsigned int, unsigned int>, node>::iterator
         it = _services->begin(),
         end = _services->end();
       it != end;
       ++it) {
    std::map<unsigned int, node>::iterator it2(_hosts->find(it->first.first));
    if (it2 == _hosts->end())
      throw (exceptions::msg() << "could not find host "
               << it->first.first << " for service "
               << it->first.second);
    logging::config << logging::MEDIUM << "correlation: service "
      << it->first.second << " automatically depends on host "
      << it->first.first;
    it->second.depends_on.push_back(&(it2->second));
    it2->second.depended_by.push_back(&(it->second));
  }
  return ;
}

/**
 *  Find a node with its host_id and optionally its service_id.
 *
 *  @param[in] host_id    String of the host_id.
 *  @param[in] service_id Potentially NULL string of the service_id.
 *
 *  @return Node matching host_id/service_id.
 */
node* parser::_find_node(char const* host_id, char const* service_id) {
  node* n(NULL);
  if (!service_id) {
    std::map<unsigned int, node>::iterator it(
      _hosts->find(strtoul(host_id, NULL, 0)));
    if (it != _hosts->end())
      n = &it->second;
  }
  else {
    std::map<std::pair<unsigned int, unsigned int>, node>::iterator it(
      _services->find(std::make_pair(strtoul(host_id, NULL, 0),
        strtoul(service_id, NULL, 0))));
    if (it != _services->end())
      n = &it->second;
  }
  return (n);
}

bool parser::startElement(QString const& uri,
                          QString const& localname,
                          QString const& qname,
                          QXmlAttributes const& attrs) {
  (void)uri;
  (void)qname;
  if (!_in_root)
    _in_root = true;
  else {
    char const* value(localname.toStdString().c_str());
    if (!strcmp(value, "dependency")) {
      QString hi1;
      QString hi2;
      node* n1 = NULL;
      node* n2 = NULL;
      QString si1;
      QString si2;

      // Fetch attributes of the XML node.
      hi1 = attrs.value("dependent_host");
      hi2 = attrs.value("host");
      si1 = attrs.value("dependent_service");
      si2 = attrs.value("service");
      if (!hi1.size() || !hi2.size())
        throw (exceptions::msg() << "missing an host id for an " \
                 "element of a dependency definition");

      // Process these attributes.
      n1 = _find_node(qPrintable(hi1), (si1.size() ? qPrintable(si1) : NULL));
      n2 = _find_node(qPrintable(hi2), (si2.size() ? qPrintable(si2) : NULL));
      if (n1 && n2) {
        logging::config << logging::MEDIUM << "correlation: node ("
          << n1->host_id << ", " << n1->service_id
          << ") depends on node (" << n2->host_id << ", "
          << n2->service_id << ")";
        n1->depends_on.push_back(n2);
        n2->depended_by.push_back(n1);
      }
    }
    else if (!strcmp(value, "host")) {
      QString i_attr;
      node n;

      // Get XML node attribute.
      i_attr = attrs.value("id");
      if (!i_attr.size())
        throw (exceptions::msg() << "could not find an 'id' attribute" \
                 " on a 'host' definition");

      // Process attribute.
      n.host_id = strtoul(i_attr.toStdString().c_str(), NULL, 0);
      (*_hosts)[n.host_id] = n;
      logging::config << logging::MEDIUM
        << "correlation: new host " << n.host_id;
    }
    else if (!strcmp(value, "parent")) {
      QString host_attr;
      QString parent_attr;
      std::map<unsigned int, node>::iterator it1;
      std::map<unsigned int, node>::iterator it2;

      // Get XML node attributes.
      host_attr = attrs.value("host");
      parent_attr = attrs.value("parent");
      if (!host_attr.size() || !parent_attr.size())
        throw (exceptions::msg() << "could not find 'host' or " \
                 "'parent' attribute of a parenting definition");

      // Process attributes.
      it1 = (*_hosts).find(strtoul(host_attr.toStdString().c_str(),
        NULL,
        0));
      it2 = (*_hosts).find(strtoul(parent_attr.toStdString().c_str(),
        NULL,
        0));
      if ((it1 != (*_hosts).end()) && (it2 != (*_hosts).end())) {
        logging::config << logging::MEDIUM << "correlation: host "
          << it2->second.host_id << " is parent of host "
          << it1->second.host_id;
        it1->second.parents.push_back(&it2->second);
        it2->second.children.push_back(&it1->second);
      }
    }
    else if (!strcmp(value, "service")) {
      QString host_attr;
      QString id_attr;
      node n;

      // Get XML node attributes.
      host_attr = attrs.value("host");
      id_attr = attrs.value("id");
      if (!host_attr.size() || !id_attr.size())
        throw (exceptions::msg() << "could not find 'host' or 'id' " \
                 "attribute of a 'service' definition");

      // Process attributes.
      n.host_id = strtoul(host_attr.toStdString().c_str(), NULL, 0);
      n.service_id = strtoul(id_attr.toStdString().c_str(), NULL, 0);
      (*_services)[std::make_pair(n.host_id, n.service_id)] = n;
      logging::config << logging::MEDIUM
        << "correlation: new service (" << n.host_id << ", "
        << n.service_id << ")";
    }
  }
  return (true);
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
parser::parser() {}

/**
 *  Copy constructor.
 *
 *  @param[in] p Unused.
 */
parser::parser(parser const& p) : QXmlDefaultHandler() {
  (void)p;
}

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

/**
 *  Assignment operator.
 *
 *  @param[in] p Unused.
 *
 *  @return *this
 */
parser& parser::operator=(parser const& p) {
  (void)p;
  return (*this);
}

/**
 *  Parse a configuration file.
 *
 *  @param[in]  filename Path to the correlation file.
 *  @param[out] hosts    List of hosts.
 *  @param[out] services List of services.
 */
void parser::parse(QString const& filename,
                   std::map<unsigned int, node>& hosts,
                   std::map<std::pair<unsigned int, unsigned int>, node>& services) {
  QXmlSimpleReader reader;
  _hosts = &hosts;
  _services = &services;
  try {
    reader.setContentHandler(this);
    reader.setErrorHandler(this);
    QFile qf(filename);
    if (!qf.open(QIODevice::ReadOnly))
      throw (exceptions::msg() << qf.errorString());
    std::auto_ptr<QXmlInputSource> source(new QXmlInputSource(&qf));
    reader.parse(source.get());
    _auto_services_dependencies();
  }
  catch (QXmlParseException const& e) {
    logging::config << logging::HIGH << "correlation: parsing error " \
         "on \"" << filename << "\" (line "
      << (unsigned int)e.lineNumber() << ", character "
      << (unsigned int)e.columnNumber() << "): " << e.message();
  }
  catch (exceptions::msg const& e) {
    logging::config << logging::HIGH << "correlation: error while " \
      "parsing correlation file \"" << filename << "\": " << e.what();
  }
  return ;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#if !defined LABEL_COLLISION_DETECTOR
#define LABEL_COLLISION_DETECTOR
// mapnik
#include <mapnik/quad_tree.hpp>
#include <mapnik/value.hpp>
// stl
#include <vector>
#include <unicode/unistr.h>

namespace mapnik
{
   //this needs to be tree structure
   //as a proof of a concept _only_ we use sequential scan

   struct label_collision_detector
   {
         typedef std::vector<Envelope<double> > label_placements;

         bool has_plasement(Envelope<double> const& box)
         {
            label_placements::const_iterator itr=labels_.begin();
            for( ; itr !=labels_.end();++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }
            labels_.push_back(box);
            return true;
         }
         void clear()
         {
            labels_.clear();
         }

      private:

         label_placements labels_;
   };

   // quad_tree based label collision detector
   class label_collision_detector2 : boost::noncopyable
   {
         typedef quad_tree<Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector2(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            tree_.insert(box,box);
            return true;
         }

         void clear()
         {
            tree_.clear();
         }

   };

   // quad_tree based label collision detector with seperate check/insert
   class label_collision_detector3 : boost::noncopyable
   {
         typedef quad_tree< Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector3(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            return true;
         }

         void insert(Envelope<double> const& box)
         {
            tree_.insert(box, box);
         }

         void clear()
         {
            tree_.clear();
         }
   };

   //quad tree based label collission detector so labels dont appear within a given distance
   class label_collision_detector4 : boost::noncopyable
   {
         struct label
         {
               label(Envelope<double> const& b) : box(b) {}
               label(Envelope<double> const& b, UnicodeString const& t) : box(b), text(t) {}

               Envelope<double> box;
               UnicodeString text;
         };

         typedef quad_tree< label > tree_t;
         Envelope<double> extent_;
         tree_t tree_;

    public:

        explicit label_collision_detector4(Envelope<double> const& extent)
           : extent_(extent),
             tree_(extent) {}

        bool has_placement(Envelope<double> const& box)
        {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->box.intersects(box))
               {
                  return false;
               }
            }

            return true;
        }

        bool has_placement(Envelope<double> const& box, UnicodeString const& text, double distance)
        {
            Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
            tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
                {
                    return false;
                }
            }

            return true;
        }

      bool has_point_placement(Envelope<double> const& box, UnicodeString const& text, double distance)
      {
         Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
         tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->box.intersects(bigger_box))
            {
               return false;
            }
         }

         return true;
      }

      void insert(Envelope<double> const& box)
      {
            tree_.insert(label(box), box);
         }

         void insert(Envelope<double> const& box, UnicodeString const& text)
         {
            tree_.insert(label(box, text), box);
         }

         void clear()
         {
            tree_.clear();
         }
         Envelope<double> const& extent() const
         {
            return extent_;
         }
    };
}

#endif
<commit_msg>+ minor formatting <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#if !defined LABEL_COLLISION_DETECTOR
#define LABEL_COLLISION_DETECTOR
// mapnik
#include <mapnik/quad_tree.hpp>
#include <mapnik/value.hpp>
// stl
#include <vector>
#include <unicode/unistr.h>

namespace mapnik
{
   //this needs to be tree structure
   //as a proof of a concept _only_ we use sequential scan

   struct label_collision_detector
   {
      typedef std::vector<Envelope<double> > label_placements;

      bool has_plasement(Envelope<double> const& box)
      {
         label_placements::const_iterator itr=labels_.begin();
         for( ; itr !=labels_.end();++itr)
         {
            if (itr->intersects(box))
            {
               return false;
            }
         }
         labels_.push_back(box);
         return true;
      }
      void clear()
      {
         labels_.clear();
      }

   private:

      label_placements labels_;
   };

   // quad_tree based label collision detector
   class label_collision_detector2 : boost::noncopyable
   {
      typedef quad_tree<Envelope<double> > tree_t;
      tree_t tree_;
   public:

      explicit label_collision_detector2(Envelope<double> const& extent)
         : tree_(extent) {}

      bool has_placement(Envelope<double> const& box)
      {
         tree_t::query_iterator itr = tree_.query_in_box(box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->intersects(box))
            {
               return false;
            }
         }

         tree_.insert(box,box);
         return true;
      }

      void clear()
      {
         tree_.clear();
      }

   };

   // quad_tree based label collision detector with seperate check/insert
   class label_collision_detector3 : boost::noncopyable
   {
      typedef quad_tree< Envelope<double> > tree_t;
      tree_t tree_;
   public:

      explicit label_collision_detector3(Envelope<double> const& extent)
         : tree_(extent) {}

      bool has_placement(Envelope<double> const& box)
      {
         tree_t::query_iterator itr = tree_.query_in_box(box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->intersects(box))
            {
               return false;
            }
         }

         return true;
      }

      void insert(Envelope<double> const& box)
      {
         tree_.insert(box, box);
      }

      void clear()
      {
         tree_.clear();
      }
   };

   //quad tree based label collission detector so labels dont appear within a given distance
   class label_collision_detector4 : boost::noncopyable
   {
      struct label
      {
         label(Envelope<double> const& b) : box(b) {}
         label(Envelope<double> const& b, UnicodeString const& t) : box(b), text(t) {}

         Envelope<double> box;
         UnicodeString text;
      };

      typedef quad_tree< label > tree_t;
      Envelope<double> extent_;
      tree_t tree_;

   public:

      explicit label_collision_detector4(Envelope<double> const& extent)
         : extent_(extent),
           tree_(extent) {}

      bool has_placement(Envelope<double> const& box)
      {
         tree_t::query_iterator itr = tree_.query_in_box(box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->box.intersects(box))
            {
               return false;
            }
         }

         return true;
      }

      bool has_placement(Envelope<double> const& box, UnicodeString const& text, double distance)
      {
         Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
         tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
            {
               return false;
            }
         }

         return true;
      }

      bool has_point_placement(Envelope<double> const& box, UnicodeString const& text, double distance)
      {
         Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
         tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
         tree_t::query_iterator end = tree_.query_end();

         for ( ;itr != end; ++itr)
         {
            if (itr->box.intersects(bigger_box))
            {
               return false;
            }
         }

         return true;
      }

      void insert(Envelope<double> const& box)
      {
         tree_.insert(label(box), box);
      }

      void insert(Envelope<double> const& box, UnicodeString const& text)
      {
         tree_.insert(label(box, text), box);
      }

      void clear()
      {
         tree_.clear();
      }

      Envelope<double> const& extent() const
      {
         return extent_;
      }
   };
}

#endif
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <algorithm>
#include <cstring>
#ifndef NDEBUG
#include <iostream>
#endif

#include <GL/glew.h>

#include <visionaray/gl/compositing.h>
#include <visionaray/gl/handle.h>
#include <visionaray/gl/util.h>
#include <visionaray/aligned_vector.h>

#define VSNRAY_CPU_BUFFER_TEX 1

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// Private implementation
//

template <pixel_format ColorFormat, pixel_format DepthFormat>
struct cpu_buffer_rt<ColorFormat, DepthFormat>::impl
{
    impl() : compositor(nullptr) {}

    std::unique_ptr<gl::depth_compositor>   compositor;

    aligned_vector<color_type>              color_buffer;
    aligned_vector<depth_type>              depth_buffer;
};

//-------------------------------------------------------------------------------------------------
// cpu_buffer_rt
//

template <pixel_format ColorFormat, pixel_format DepthFormat>
cpu_buffer_rt<ColorFormat, DepthFormat>::cpu_buffer_rt()
    : impl_(new impl)
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
cpu_buffer_rt<ColorFormat, DepthFormat>::~cpu_buffer_rt()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type* cpu_buffer_rt<ColorFormat, DepthFormat>::color()
{
    return impl_->color_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type* cpu_buffer_rt<ColorFormat, DepthFormat>::depth()
{
    return impl_->depth_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type const* cpu_buffer_rt<ColorFormat, DepthFormat>::color() const
{
    return impl_->color_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type const* cpu_buffer_rt<ColorFormat, DepthFormat>::depth() const
{
    return impl_->depth_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::ref_type cpu_buffer_rt<ColorFormat, DepthFormat>::ref()
{
    return typename cpu_buffer_rt<ColorFormat, DepthFormat>::ref_type(
            color(),
            depth(),
            width(),
            height()
            );
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::clear_color(typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type color)
{
    std::fill(impl_->color_buffer.begin(), impl_->color_buffer.end(), color);
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::clear_depth(typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type depth)
{
    std::fill(impl_->depth_buffer.begin(), impl_->depth_buffer.end(), depth);
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::begin_frame()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::end_frame()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::resize(size_t w, size_t h)
{
    render_target::resize(w, h);

    // Allocate storage

    impl_->color_buffer.resize(w * h);

    if (DepthFormat != PF_UNSPECIFIED)
    {
        impl_->depth_buffer.resize(w * h);
    }

#if VSNRAY_CPU_BUFFER_TEX

    glPushAttrib( GL_TEXTURE_BIT );

    if (!impl_->compositor)
    {
        impl_->compositor.reset(new gl::depth_compositor);
    }

    // Allocate texture storage

    pixel_format_info cinfo = map_pixel_format(ColorFormat);

    impl_->compositor->setup_color_texture(cinfo, w, h);

    if (DepthFormat != PF_UNSPECIFIED)
    {
        pixel_format_info dinfo = map_pixel_format(DepthFormat);

        impl_->compositor->setup_depth_texture(dinfo, w, h);
    }

    glPopAttrib();

#endif
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::display_color_buffer() const
{
#if VSNRAY_CPU_BUFFER_TEX

    if (DepthFormat != PF_UNSPECIFIED)
    {
        glPushAttrib( GL_TEXTURE_BIT | GL_ENABLE_BIT );

        // Update color texture

        pixel_format_info cinfo = map_pixel_format(ColorFormat);

        impl_->compositor->update_color_texture(
                cinfo,
                width(),
                height(),
                impl_->color_buffer.data()
                );

        // Update depth texture

        pixel_format_info dinfo = map_pixel_format(DepthFormat);

        impl_->compositor->update_depth_texture(
                dinfo,
                width(),
                height(),
                impl_->depth_buffer.data()
                );

        // Combine textures using a shader

        impl_->compositor->composite_textures();

        glPopAttrib();
    }
    else
    {
        pixel_format_info cinfo = map_pixel_format(ColorFormat);

        impl_->compositor->update_color_texture(
                cinfo,
                width(),
                height(),
                impl_->color_buffer.data()
                );

        impl_->compositor->display_color_texture();
    }

#else

    // Use glDrawPixels

    if (DepthFormat != PF_UNSPECIFIED)
    {
        glPushAttrib( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ENABLE_BIT );

        glEnable(GL_STENCIL_TEST);
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
        glStencilFunc(GL_ALWAYS, 1, 1);
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

        pixel_format_info dinfo = map_pixel_format(DepthFormat);
        gl::blend_pixels( width(), height(), dinfo.format, dinfo.type, impl_->depth_buffer.data() );

        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glStencilFunc(GL_EQUAL, 1, 1);
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        glDisable(GL_DEPTH_TEST);

        pixel_format_info cinfo = map_pixel_format(ColorFormat);
        gl::blend_pixels( width(), height(), cinfo.format, cinfo.type, impl_->color_buffer.data() );

        glPopAttrib();
    }
    else
    {
        pixel_format_info info = map_pixel_format(ColorFormat);
        gl::blend_pixels( width(), height(), info.format, info.type, impl_->color_buffer.data() );
    }

#endif
}

} // visionaray
<commit_msg>Remove unnecessary include<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <algorithm>
#include <cstring>

#include <GL/glew.h>

#include <visionaray/gl/compositing.h>
#include <visionaray/gl/handle.h>
#include <visionaray/gl/util.h>
#include <visionaray/aligned_vector.h>

#define VSNRAY_CPU_BUFFER_TEX 1

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// Private implementation
//

template <pixel_format ColorFormat, pixel_format DepthFormat>
struct cpu_buffer_rt<ColorFormat, DepthFormat>::impl
{
    impl() : compositor(nullptr) {}

    std::unique_ptr<gl::depth_compositor>   compositor;

    aligned_vector<color_type>              color_buffer;
    aligned_vector<depth_type>              depth_buffer;
};

//-------------------------------------------------------------------------------------------------
// cpu_buffer_rt
//

template <pixel_format ColorFormat, pixel_format DepthFormat>
cpu_buffer_rt<ColorFormat, DepthFormat>::cpu_buffer_rt()
    : impl_(new impl)
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
cpu_buffer_rt<ColorFormat, DepthFormat>::~cpu_buffer_rt()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type* cpu_buffer_rt<ColorFormat, DepthFormat>::color()
{
    return impl_->color_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type* cpu_buffer_rt<ColorFormat, DepthFormat>::depth()
{
    return impl_->depth_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type const* cpu_buffer_rt<ColorFormat, DepthFormat>::color() const
{
    return impl_->color_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type const* cpu_buffer_rt<ColorFormat, DepthFormat>::depth() const
{
    return impl_->depth_buffer.data();
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
typename cpu_buffer_rt<ColorFormat, DepthFormat>::ref_type cpu_buffer_rt<ColorFormat, DepthFormat>::ref()
{
    return typename cpu_buffer_rt<ColorFormat, DepthFormat>::ref_type(
            color(),
            depth(),
            width(),
            height()
            );
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::clear_color(typename cpu_buffer_rt<ColorFormat, DepthFormat>::color_type color)
{
    std::fill(impl_->color_buffer.begin(), impl_->color_buffer.end(), color);
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::clear_depth(typename cpu_buffer_rt<ColorFormat, DepthFormat>::depth_type depth)
{
    std::fill(impl_->depth_buffer.begin(), impl_->depth_buffer.end(), depth);
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::begin_frame()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::end_frame()
{
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::resize(size_t w, size_t h)
{
    render_target::resize(w, h);

    // Allocate storage

    impl_->color_buffer.resize(w * h);

    if (DepthFormat != PF_UNSPECIFIED)
    {
        impl_->depth_buffer.resize(w * h);
    }

#if VSNRAY_CPU_BUFFER_TEX

    glPushAttrib( GL_TEXTURE_BIT );

    if (!impl_->compositor)
    {
        impl_->compositor.reset(new gl::depth_compositor);
    }

    // Allocate texture storage

    pixel_format_info cinfo = map_pixel_format(ColorFormat);

    impl_->compositor->setup_color_texture(cinfo, w, h);

    if (DepthFormat != PF_UNSPECIFIED)
    {
        pixel_format_info dinfo = map_pixel_format(DepthFormat);

        impl_->compositor->setup_depth_texture(dinfo, w, h);
    }

    glPopAttrib();

#endif
}

template <pixel_format ColorFormat, pixel_format DepthFormat>
void cpu_buffer_rt<ColorFormat, DepthFormat>::display_color_buffer() const
{
#if VSNRAY_CPU_BUFFER_TEX

    if (DepthFormat != PF_UNSPECIFIED)
    {
        glPushAttrib( GL_TEXTURE_BIT | GL_ENABLE_BIT );

        // Update color texture

        pixel_format_info cinfo = map_pixel_format(ColorFormat);

        impl_->compositor->update_color_texture(
                cinfo,
                width(),
                height(),
                impl_->color_buffer.data()
                );

        // Update depth texture

        pixel_format_info dinfo = map_pixel_format(DepthFormat);

        impl_->compositor->update_depth_texture(
                dinfo,
                width(),
                height(),
                impl_->depth_buffer.data()
                );

        // Combine textures using a shader

        impl_->compositor->composite_textures();

        glPopAttrib();
    }
    else
    {
        pixel_format_info cinfo = map_pixel_format(ColorFormat);

        impl_->compositor->update_color_texture(
                cinfo,
                width(),
                height(),
                impl_->color_buffer.data()
                );

        impl_->compositor->display_color_texture();
    }

#else

    // Use glDrawPixels

    if (DepthFormat != PF_UNSPECIFIED)
    {
        glPushAttrib( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ENABLE_BIT );

        glEnable(GL_STENCIL_TEST);
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
        glStencilFunc(GL_ALWAYS, 1, 1);
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

        pixel_format_info dinfo = map_pixel_format(DepthFormat);
        gl::blend_pixels( width(), height(), dinfo.format, dinfo.type, impl_->depth_buffer.data() );

        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glStencilFunc(GL_EQUAL, 1, 1);
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        glDisable(GL_DEPTH_TEST);

        pixel_format_info cinfo = map_pixel_format(ColorFormat);
        gl::blend_pixels( width(), height(), cinfo.format, cinfo.type, impl_->color_buffer.data() );

        glPopAttrib();
    }
    else
    {
        pixel_format_info info = map_pixel_format(ColorFormat);
        gl::blend_pixels( width(), height(), info.format, info.type, impl_->color_buffer.data() );
    }

#endif
}

} // visionaray
<|endoftext|>


<commit_before>/*
This file is a part of NNTL project (https://github.com/Arech/nntl)

Copyright (c) 2015, Arech (aradvert@gmail.com; https://github.com/Arech)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of NNTL nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// tests.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "../nntl/interface/math.h"
#include "../nntl/nntl.h"
#include "../nntl/_supp/binfile.h"

using namespace nntl;
typedef nntl_supp::binfile reader_t;
using float_t_ = math_types::float_ty;

#if defined(TESTS_SKIP_NNET_LONGRUNNING)
//ALWAYS run debug build with similar relations of data sizes:
// if release will run in minibatches - make sure, there will be at least 2 minibatches)
// if release will use different data sizes for train/test - make sure, debug will also run on different datasizes
#define MNIST_FILE "../data/mnist200_100.bin"
#else
#define MNIST_FILE "../data/mnist60000.bin"
#endif // _DEBUG

TEST(TestNntl, Training) {
	train_data td;
	reader_t reader;

	STDCOUTL("Reading datafile '" << MNIST_FILE << "'...");
	reader_t::ErrorCode rec = reader.read(NNTL_STRING(MNIST_FILE), td);
	ASSERT_EQ(reader_t::ErrorCode::Success, rec) << "Error code description: " << reader.get_last_error_str();
	ASSERT_TRUE(td.train_x().emulatesBiases());
	ASSERT_TRUE(td.test_x().emulatesBiases());

	const float_t_ dropoutFrac = 0, momentum = 0.0;
	//const ILR ilr(.9, 1.1, .00000001, 1000);

	layer_input inp(td.train_x().cols_no_bias());

#ifdef TESTS_SKIP_NNET_LONGRUNNING
	size_t epochs = 5;
	const float_t_ learningRate = .01;

	layer_fully_connected<> fcl(60, learningRate, dropoutFrac);
	layer_fully_connected<> fcl2(60, learningRate, dropoutFrac);
	//layer_fully_connected<> fcl3(15,learningRate,	 dropoutFrac);

#else
	size_t epochs = 20;
	const float_t_ learningRate = .01;

	layer_fully_connected<activation::sigm> fcl(500, learningRate,dropoutFrac);
	layer_fully_connected<activation::sigm> fcl2(300, learningRate, dropoutFrac);
#endif // TESTS_SKIP_LONGRUNNING

	auto optType = decltype(fcl)::grad_works_t::ClassicalConstant;
	fcl.m_gradientWorks.set_momentum(momentum, false).set_type(optType);
	//fcl.m_gradientWorks.set_type(decltype(fcl)::grad_works_t::ModProp).set_nesterov_momentum(.95);

	fcl2.m_gradientWorks.set_momentum(momentum, false).set_type(optType);
	//fcl2.m_gradientWorks.set_type(decltype(fcl2)::grad_works_t::ModProp).set_nesterov_momentum(.95);

	layer_output<activation::sigm_quad_loss> outp(td.train_y().cols(), learningRate);
	outp.m_gradientWorks.set_momentum(momentum, false).set_type(optType);

	//uncomment to turn on derivative value restriction
	//outp.restrict_dL_dZ(float_t_(-10), float_t_(10));

	auto lp = make_layers_pack(inp, fcl, fcl2, outp);
	//auto lp = make_layers_pack(inp, fcl, fcl2, fcl3, fcl4, outp);

	nnet_cond_epoch_eval cee(epochs);
	nnet_train_opts<decltype(cee)> opts(std::move(cee));

	//const int batchSize = 100 * 6 * 100;
	opts.batchSize(100);

	auto nn = make_nnet(lp);

	auto ec = nn.train(td, opts);

	ASSERT_EQ(decltype(nn)::ErrorCode::Success, ec) << "Error code description: " << nn.get_last_error_string();
}

int __cdecl main(int argc, char **argv) {
#ifdef _DEBUG
	STDCOUTL("\n******\n*** This is DEBUG binary! All performance reports are invalid!\n******\n");
#endif // _DEBUG

	::testing::InitGoogleTest(&argc, argv);

	int r = RUN_ALL_TESTS();
	//std::cin.ignore();
	return r;
}
<commit_msg>fixes<commit_after>/*
This file is a part of NNTL project (https://github.com/Arech/nntl)

Copyright (c) 2015, Arech (aradvert@gmail.com; https://github.com/Arech)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of NNTL nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// tests.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include "../nntl/interface/math.h"
#include "../nntl/nntl.h"
#include "../nntl/_supp/binfile.h"

using namespace nntl;
typedef nntl_supp::binfile reader_t;
using float_t_ = math_types::float_ty;

#if defined(TESTS_SKIP_NNET_LONGRUNNING)
//ALWAYS run debug build with similar relations of data sizes:
// if release will run in minibatches - make sure, there will be at least 2 minibatches)
// if release will use different data sizes for train/test - make sure, debug will also run on different datasizes
#define MNIST_FILE "../data/mnist200_100.bin"
#else
#define MNIST_FILE "../data/mnist60000.bin"
#endif // _DEBUG

TEST(TestNntl, Training) {
	train_data td;
	reader_t reader;

	STDCOUTL("Reading datafile '" << MNIST_FILE << "'...");
	reader_t::ErrorCode rec = reader.read(NNTL_STRING(MNIST_FILE), td);
	ASSERT_EQ(reader_t::ErrorCode::Success, rec) << "Error code description: " << reader.get_last_error_str();
	ASSERT_TRUE(td.train_x().emulatesBiases());
	ASSERT_TRUE(td.test_x().emulatesBiases());

	const float_t_ dropoutFrac = 0, momentum = 0.0;
	//const ILR ilr(.9, 1.1, .00000001, 1000);

	layer_input inp(td.train_x().cols_no_bias());

#ifdef TESTS_SKIP_NNET_LONGRUNNING
	size_t epochs = 5;
	const float_t_ learningRate = .7;

	layer_fully_connected<> fcl(60, learningRate, dropoutFrac);
	layer_fully_connected<> fcl2(50, learningRate, dropoutFrac);
	//layer_fully_connected<> fcl3(15,learningRate,	 dropoutFrac);

#else
	size_t epochs = 20;
	const float_t_ learningRate = 0.7;

	layer_fully_connected<activation::sigm<>> fcl(500, learningRate,dropoutFrac);
	layer_fully_connected<activation::sigm<>> fcl2(300, learningRate, dropoutFrac);
#endif // TESTS_SKIP_LONGRUNNING

	const bool bSetMN = false;
	const float_t_ mul = 1.0 / 10000.0;
	auto optType = decltype(fcl)::grad_works_t::ClassicalConstant;

	fcl.m_gradientWorks.set_momentum(momentum, false).set_type(optType)
		.set_weight_vector_max_norm2(bSetMN ? mul * 768 * 768 : 0, true);
	fcl2.m_gradientWorks.set_momentum(momentum, false).set_type(optType)
		.set_weight_vector_max_norm2(bSetMN ? mul * 500 * 500 : 0, true);

	layer_output<activation::sigm_quad_loss<>> outp(td.train_y().cols(), learningRate);
	outp.m_gradientWorks.set_momentum(momentum, false).set_type(optType)
		.set_weight_vector_max_norm2(bSetMN ? mul * 300 * 300 : 0, true);

	//uncomment to turn on derivative value restriction
	//outp.restrict_dL_dZ(float_t_(-10), float_t_(10));

	auto lp = make_layers_pack(inp, fcl, fcl2, outp);
	//auto lp = make_layers_pack(inp, fcl, fcl2, fcl3, fcl4, outp);

	nnet_cond_epoch_eval cee(epochs);
	nnet_train_opts<decltype(cee)> opts(std::move(cee));

	//const int batchSize = 100 * 6 * 100;
	opts.batchSize(100);

	auto nn = make_nnet(lp);

	auto ec = nn.train(td, opts);

	ASSERT_EQ(decltype(nn)::ErrorCode::Success, ec) << "Error code description: " << nn.get_last_error_string();
}

int __cdecl main(int argc, char **argv) {
#ifdef _DEBUG
	STDCOUTL("\n******\n*** This is DEBUG binary! All performance reports are invalid!\n******\n");
#endif // _DEBUG

	::testing::InitGoogleTest(&argc, argv);

	int r = RUN_ALL_TESTS();
	//std::cin.ignore();
	return r;
}
<|endoftext|>


<commit_before>//================================================================================
//
//	The MIT License (MIT)
//
//	Copyright (c) 2014 Konstantinos Sofokleous
//
//	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 SLOG_DISABLE 0
//#define SLOG_DISABLE_INFO 0
#include <slog/slog.h>

void compare_file_contents(const char* filename, std::string contents, std::string errorstring)
{
	std::ifstream file(filename);
	if (file.bad())
		throw std::runtime_error(strobj() << "compare_file_contents :: file '" << filename << "'");

	std::string value;
	file >> value;

	if (value.compare(contents) != 0)
		throw std::runtime_error(strobj() << errorstring);
}

/// --- tests

void emptylog(int argc, char* argv[])
{
	const char logfilename[] = "emptylog.test.log";
	if (_unlink(logfilename) != 0 && (errno != ENOENT))
		throw std::runtime_error(strobj() << "emptylog :: failed to delete file '" << logfilename << "'");

	{
		slog::filelogdevice logfile(logfilename, true);
		slog::info::type.enabled = false;
		slog::info() << "test";
		slog::info::type.enabled = true;
	}

	compare_file_contents(logfilename, "", "type.enabled = false; failed not to write to log file");
}

void simple_log_line(int argc, char* argv[])
{
	const char thisline[] = "this simple line";

	auto prevtime = slog::logconfig::timestamps;
	auto prevprintlogtype = slog::logconfig::print_logtype;
	slog::logconfig::timestamps = false;
	slog::logconfig::print_logtype = false;

	slog::logconfig::set_default_console_print([&thisline](const slog::logtype& type, const std::string& line)
	{
		if (line.compare(thisline) != 0)
			throw std::runtime_error(strobj() << "simple_log_line :: failed compose a simple log line with all prefixes removed");
	});

	slog::info() << thisline;

	slog::logconfig::timestamps = prevtime;
	slog::logconfig::print_logtype = prevprintlogtype;
	slog::logconfig::set_default_console_print(nullptr);
}

void default_verbose_debug_off(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() > 0)
			throw std::runtime_error(strobj() << "default_verbose_debug_off :: default state of verbose and debug is not disabled");
	});

	slog::debug() << "testing";
	slog::verbose() << "testing again";

	slog::logconfig::set_default_console_print(nullptr);
}

void empty_lines_should_print(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() == 0)
			throw std::runtime_error(strobj() << "empty_lines_should_print :: empty info line printed nothing");
	});

	slog::info();

	slog::logconfig::set_default_console_print(nullptr);
}

// -------------------------------------------------------------------------------------

#include <iostream>

int main(int argc, char* argv[])
{
	try
	{
		emptylog(argc, argv);
		simple_log_line(argc, argv);
		default_verbose_debug_off(argc, argv);
		empty_lines_should_print(argc, argv);

		slog::logconfig::parse(argc, argv);

		{
			slog::filelogdevice keep_this_instance_around("logoutput.log", true);

			slog::info();
			slog::info() << "---------------- NEW RUN ----------------";
			slog::info() << "slog version " << slog::getmajorversion() << "." << slog::getminorversion() << "." << slog::getpatchversion();

			slog::error() << "major error: failed to say hello to world";
			slog::warn() << "warning: this should be yellow";
			slog::info() << "fyi: life is full of meaningless little lines";
			slog::verbose() << "verbosity: also known as 'it goes to eleven'";
			slog::success() << "success: you only see this when you get lucky";
		}

		slog::debug() << "major debug reporting for duty... this log wont make in the log file";
	}
	catch (std::exception& e)
	{
		std::cerr << "Test failed: " << e.what() << std::endl;
		return -1;
	}

	std::cout << "All tests succeeded" << std::endl;

	return 0;
}<commit_msg>fixed unlink not compiling on linux<commit_after>//================================================================================
//
//	The MIT License (MIT)
//
//	Copyright (c) 2014 Konstantinos Sofokleous
//
//	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 SLOG_DISABLE 0
//#define SLOG_DISABLE_INFO 0
#include <slog/slog.h>

#ifdef _MSC_VER
#define unlink _unlink
#else
#include <unistd.h>
#endif

void compare_file_contents(const char* filename, std::string contents, std::string errorstring)
{
	std::ifstream file(filename);
	if (file.bad())
		throw std::runtime_error(strobj() << "compare_file_contents :: file '" << filename << "'");

	std::string value;
	file >> value;

	if (value.compare(contents) != 0)
		throw std::runtime_error(strobj() << errorstring);
}

/// --- tests

void emptylog(int argc, char* argv[])
{
	const char logfilename[] = "emptylog.test.log";
	if (unlink(logfilename) != 0 && (errno != ENOENT))
		throw std::runtime_error(strobj() << "emptylog :: failed to delete file '" << logfilename << "'");

	{
		slog::filelogdevice logfile(logfilename, true);
		slog::info::type.enabled = false;
		slog::info() << "test";
		slog::info::type.enabled = true;
	}

	compare_file_contents(logfilename, "", "type.enabled = false; failed not to write to log file");
}

void simple_log_line(int argc, char* argv[])
{
	const char thisline[] = "this simple line";

	auto prevtime = slog::logconfig::timestamps;
	auto prevprintlogtype = slog::logconfig::print_logtype;
	slog::logconfig::timestamps = false;
	slog::logconfig::print_logtype = false;

	slog::logconfig::set_default_console_print([&thisline](const slog::logtype& type, const std::string& line)
	{
		if (line.compare(thisline) != 0)
			throw std::runtime_error(strobj() << "simple_log_line :: failed compose a simple log line with all prefixes removed");
	});

	slog::info() << thisline;

	slog::logconfig::timestamps = prevtime;
	slog::logconfig::print_logtype = prevprintlogtype;
	slog::logconfig::set_default_console_print(nullptr);
}

void default_verbose_debug_off(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() > 0)
			throw std::runtime_error(strobj() << "default_verbose_debug_off :: default state of verbose and debug is not disabled");
	});

	slog::debug() << "testing";
	slog::verbose() << "testing again";

	slog::logconfig::set_default_console_print(nullptr);
}

void empty_lines_should_print(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() == 0)
			throw std::runtime_error(strobj() << "empty_lines_should_print :: empty info line printed nothing");
	});

	slog::info();

	slog::logconfig::set_default_console_print(nullptr);
}

// -------------------------------------------------------------------------------------

#include <iostream>

int main(int argc, char* argv[])
{
	try
	{
		emptylog(argc, argv);
		simple_log_line(argc, argv);
		default_verbose_debug_off(argc, argv);
		empty_lines_should_print(argc, argv);

		slog::logconfig::parse(argc, argv);

		{
			slog::filelogdevice keep_this_instance_around("logoutput.log", true);

			slog::info();
			slog::info() << "---------------- NEW RUN ----------------";
			slog::info() << "slog version " << slog::getmajorversion() << "." << slog::getminorversion() << "." << slog::getpatchversion();

			slog::error() << "major error: failed to say hello to world";
			slog::warn() << "warning: this should be yellow";
			slog::info() << "fyi: life is full of meaningless little lines";
			slog::verbose() << "verbosity: also known as 'it goes to eleven'";
			slog::success() << "success: you only see this when you get lucky";
		}

		slog::debug() << "major debug reporting for duty... this log wont make in the log file";
	}
	catch (std::exception& e)
	{
		std::cerr << "Test failed: " << e.what() << std::endl;
		return -1;
	}

	std::cout << "All tests succeeded" << std::endl;

	return 0;
}
<|endoftext|>


<commit_before>
#include "IntegrateTFDH.h"

#include "Element.h"
#include "PlasmaFunctions.h"
#include "PlasmaState.h"
#include "PhysicalConstants.h"
#include "RadialFunction.h"

#include <cmath>
#include <vector>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_odeiv2.h>

#include <iostream>

namespace {

  struct TfdhParams {
    const Element& e;
    const PlasmaState& p;
    TfdhParams(const Element& re, const PlasmaState& rp) : e(re), p(rp) {}
  };

  int tfdhOde(double r, const double f[], double dfdr[], void *params) {
    const double& qe = PhysicalConstantsCGS::ElectronCharge;
    const double phi = qe*f[0]/r;
    const PlasmaState& p = static_cast<TfdhParams*>(params)->p;
    const double ne = Plasma::ne(phi, p);
    const double ionChargeDensity = Plasma::totalIonChargeDensity(phi, p);
    dfdr[0] = f[1];
    dfdr[1] = -4.0*M_PI*qe * r * (ionChargeDensity - ne);
    return 0;
  }
}

RadialFunction TFDH::solve(const Element& e, const PlasmaState& p)
{
  // set parameters here:
  const double ri = 1e-10;
  const double rf = 1e-6;

  const double dv0 = rootfindPotential(e, p, ri, rf);
  return integrateODE(e, p, dv0, ri, rf);
}

RadialFunction TFDH::integrateODE(const Element& e, const PlasmaState& p,
    const double r_init, const double r_final, const double dv0)
{
  const double dr_start = r_init;
  const double eps_abs = 1e-6;
  const double eps_rel = 0;
  TfdhParams params(e,p);
  gsl_odeiv2_system sys = {tfdhOde, nullptr, 2, &params};
  gsl_odeiv2_driver* d = gsl_odeiv2_driver_alloc_y_new(&sys,
      gsl_odeiv2_step_rk8pd, dr_start, eps_abs, eps_rel);

  // TODO -- clean all this up
  double r = r_init;
  double solution[2] = {1,2};

  std::vector<double> radii, potentials;

  const int numsteps = 100;
  for (int i=0; i<numsteps; ++i) {
    const double ri = r_init + (i+1)*(r_final-r_init)/numsteps;
    const int status = gsl_odeiv2_driver_apply(d, &r, ri, solution);
    assert(status==GSL_SUCCESS);
    radii.push_back(ri);
    potentials.push_back(solution[0]/ri);
  }

  // TODO delete the gsl stuff?

  return RadialFunction(radii, potentials);
}

double TFDH::rootfindPotential(const Element& e, const PlasmaState& p,
    const double r_init, const double r_final)
{
  // find interval that brackets correct potential
  const double dv = 1.0;
  double v0 = 0;
  double v1 = 0;

  const int num_tries = 100;
  for (int i=0; i<num_tries; ++i) {
    const auto rf = integrateODE(e, p, r_init, r_final, v0);
    if (rf.data.back() < 0.0) break;
    v1 = v0;
    v0 -= dv;
  }

  // guess a central potential
  double guess_dv0 = 1;

  // iterate guess
  // avoid fancy rootfinders here, because we aren't dealing with a smooth
  // function and its root -- rather, we are trying to find the boundary
  // between two distinct sets: dv0 too large, dv0 too small
}

<commit_msg>Fix GSL memory leak<commit_after>
#include "IntegrateTFDH.h"

#include "Element.h"
#include "PlasmaFunctions.h"
#include "PlasmaState.h"
#include "PhysicalConstants.h"
#include "RadialFunction.h"

#include <cmath>
#include <vector>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_odeiv2.h>

#include <iostream>

namespace {

  struct TfdhParams {
    const Element& e;
    const PlasmaState& p;
    TfdhParams(const Element& re, const PlasmaState& rp) : e(re), p(rp) {}
  };

  int tfdhOde(double r, const double f[], double dfdr[], void *params) {
    const double& qe = PhysicalConstantsCGS::ElectronCharge;
    const double phi = qe*f[0]/r;
    const PlasmaState& p = static_cast<TfdhParams*>(params)->p;
    const double ne = Plasma::ne(phi, p);
    const double ionChargeDensity = Plasma::totalIonChargeDensity(phi, p);
    dfdr[0] = f[1];
    dfdr[1] = -4.0*M_PI*qe * r * (ionChargeDensity - ne);
    return 0;
  }
}

RadialFunction TFDH::solve(const Element& e, const PlasmaState& p)
{
  // set parameters here:
  const double ri = 1e-10;
  const double rf = 1e-6;

  const double dv0 = rootfindPotential(e, p, ri, rf);
  return integrateODE(e, p, dv0, ri, rf);
}

RadialFunction TFDH::integrateODE(const Element& e, const PlasmaState& p,
    const double r_init, const double r_final, const double dv0)
{
  const double dr_start = r_init;
  const double eps_abs = 1e-6;
  const double eps_rel = 0;
  TfdhParams params(e,p);
  gsl_odeiv2_system sys = {tfdhOde, nullptr, 2, &params};
  gsl_odeiv2_driver* d = gsl_odeiv2_driver_alloc_y_new(&sys,
      gsl_odeiv2_step_rk8pd, dr_start, eps_abs, eps_rel);

  // TODO -- clean all this up
  double r = r_init;
  double solution[2] = {1,2};

  std::vector<double> radii, potentials;

  const int numsteps = 100;
  for (int i=0; i<numsteps; ++i) {
    const double ri = r_init + (i+1)*(r_final-r_init)/numsteps;
    const int status = gsl_odeiv2_driver_apply(d, &r, ri, solution);
    assert(status==GSL_SUCCESS);
    radii.push_back(ri);
    potentials.push_back(solution[0]/ri);
  }

  gsl_odeiv2_driver_free(d);
  return RadialFunction(radii, potentials);
}

double TFDH::rootfindPotential(const Element& e, const PlasmaState& p,
    const double r_init, const double r_final)
{
  // find interval that brackets correct potential
  const double dv = 1.0;
  double v0 = 0;
  double v1 = 0;

  const int num_tries = 100;
  for (int i=0; i<num_tries; ++i) {
    const auto rf = integrateODE(e, p, r_init, r_final, v0);
    if (rf.data.back() < 0.0) break;
    v1 = v0;
    v0 -= dv;
  }

  // guess a central potential
  double guess_dv0 = 1;

  // iterate guess
  // avoid fancy rootfinders here, because we aren't dealing with a smooth
  // function and its root -- rather, we are trying to find the boundary
  // between two distinct sets: dv0 too large, dv0 too small
}

<|endoftext|>


<commit_before>// Module:  Log4cplus
// File:    msttsappender.cxx
// Created: 10/2012
// Author:  Vaclav Zeman
//
//
//  Copyright (C) 2012-2013, Vaclav Zeman. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modifica-
//  tion, are permitted provided that the following conditions are met:
//
//  1. Redistributions of  source code must  retain the above copyright  notice,
//     this list of conditions and the following disclaimer.
//
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <log4cplus/config.hxx>
#include <log4cplus/msttsappender.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/thread/syncprims.h>

#include <iomanip>
#include <sstream>

#include <sapi.h>

namespace log4cplus
{

namespace
{

static
void
loglog_win32_error (tchar const * msg, bool dothrow = false)
{
    DWORD err = GetLastError ();
    tostringstream oss;
    oss << LOG4CPLUS_TEXT ("MSTTSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
        << err << LOG4CPLUS_TEXT (" / 0x")
        << std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
        << err;
    helpers::getLogLog ().error (oss.str (), dothrow);
}

static
void
loglog_com_error (tchar const * msg, HRESULT hr)
{
    tostringstream oss;
    oss << LOG4CPLUS_TEXT ("MSTTSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
        << hr << LOG4CPLUS_TEXT (" / 0x")
        << std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
        << hr;
    helpers::getLogLog ().error (oss.str ());
}

struct COMInitializer
{
    explicit COMInitializer (DWORD apartment_model = COINIT_APARTMENTTHREADED,
        HRESULT hr = S_OK)
        : uninit ((hr = CoInitializeEx (NULL, apartment_model)
            , hr == S_OK || hr == S_FALSE))
    { }

    ~COMInitializer ()
    {
        if (uninit)
            CoUninitialize ();
    }

    bool const uninit;
};

class SpeechObjectThread
    : public virtual log4cplus::thread::AbstractThread
{
public:
    SpeechObjectThread (ISpVoice * & ispvoice_ref)
        : ispvoice (ispvoice_ref)
    {
        terminate_ev = CreateEvent (0, true, false, 0);
        if (! terminate_ev)
            loglog_win32_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CreateEvent failed"),
                true);
    }

    ~SpeechObjectThread ()
    {
        if (! CloseHandle (terminate_ev))
            loglog_win32_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CloseHandle failed"));
    }

    virtual
    void
    run ()
    {
        COMInitializer com_init (COINIT_MULTITHREADED);

        HRESULT hr = CoCreateInstance (CLSID_SpVoice, NULL,
            CLSCTX_ALL, IID_ISpVoice, reinterpret_cast<void **>(&ispvoice));
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CoCreateInstance(IID_ISpVoice) failed"),
                hr);

        init_ev.signal ();

        for (;;)
        {
            // wait for the event and for messages
            DWORD dwReturn = 0;
            hr = ::CoWaitForMultipleHandles (0, INFINITE, 1, &terminate_ev,
                &dwReturn);

            // this thread has been reawakened. Determine why
            // and handle appropriately.
            if (hr == S_OK && dwReturn == WAIT_OBJECT_0)
                // our event happened.
                break;
            else if (FAILED (hr))
                loglog_com_error (
                    LOG4CPLUS_TEXT ("SpeechObjectThread: CoWaitForMultipleHandles() failed"),
                    hr);
        }
    };

    void
    wait_init_done () const
    {
        init_ev.wait ();
    }

    void
    terminate () const
    {
        if (! SetEvent (terminate_ev))
            loglog_win32_error (LOG4CPLUS_TEXT ("SpeechObjectThread: SetEvent failed"), true);
    }

private:
    ISpVoice * & ispvoice;
    thread::ManualResetEvent init_ev;
    HANDLE terminate_ev;
};

} // namespace

struct MSTTSAppender::Data
{
    Data ()
        : ispvoice (0)
        , async (false)
        , speak_punc (false)
    { }

    ~Data ()
    {
        if (ispvoice)
            ispvoice->Release ();
    }

    helpers::SharedObjectPtr<SpeechObjectThread> speech_thread;
    ISpVoice * ispvoice;
    bool async;
    bool speak_punc;
};

MSTTSAppender::MSTTSAppender ()
    : Appender ()
    , data (new Data)
{
    init ();
}

MSTTSAppender::MSTTSAppender (helpers::Properties const & props)
    : Appender (props)
    , data (new Data)
{
    unsigned long volume = 0;
    bool has_volume = props.getULong (volume, LOG4CPLUS_TEXT ("Volume"));
    if (has_volume)
        volume = (std::min) (volume, 100ul);

    long rate = 0;
    bool has_rate = props.getLong (rate, LOG4CPLUS_TEXT ("Rate"));
    if (has_rate)
        rate = (std::max) (-10l, (std::min) (rate, 10l));

    bool async;
    async = props.getBool (async, LOG4CPLUS_TEXT ("Async")) && async;

    bool speak_punc;
    speak_punc = props.getBool (speak_punc, LOG4CPLUS_TEXT ("SpeakPunc"))
        && speak_punc;

    init (has_rate ? &rate : 0, has_volume ? &volume : 0, speak_punc, async);
}

MSTTSAppender::~MSTTSAppender ()
{
    destructorImpl ();
    delete data;
}

void
MSTTSAppender::init (long const * rate, unsigned long const * volume,
    bool speak_punc, bool async)
{
    data->speech_thread =
        helpers::SharedObjectPtr<SpeechObjectThread> (
            new SpeechObjectThread (data->ispvoice));
    data->speech_thread->start ();
    data->speech_thread->wait_init_done ();

    COMInitializer com_init;

    HRESULT hr = S_OK;

    if (rate)
    {
        hr = data->ispvoice->SetRate (*rate);
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: SetRate failed"), hr);
    }

    if (volume)
    {
        hr = data->ispvoice->SetVolume (static_cast<USHORT>(*volume));
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: SetVolume failed"), hr);
    }

    data->async = async;
    data->speak_punc = speak_punc;
}

void
MSTTSAppender::close ()
{
    data->speech_thread->terminate ();
    data->speech_thread->join ();
}

void
MSTTSAppender::append (spi::InternalLoggingEvent const & ev)
{
    if (! data->ispvoice)
        return;

    // TODO: Expose log4cplus' internal TLS to use here.
    tostringstream oss;
    layout->formatAndAppend(oss, ev);

    DWORD flags = SPF_IS_NOT_XML;

    if (data->async)
        flags |= SPF_ASYNC;

    if (data->speak_punc)
        flags |= SPF_NLP_SPEAK_PUNC;

    COMInitializer com_init;
    HRESULT hr = data->ispvoice->Speak (
        helpers::towstring (oss.str ()).c_str (), flags, NULL);
    if (FAILED (hr))
        loglog_com_error (LOG4CPLUS_TEXT ("Speak failed"), hr);
}

void
MSTTSAppender::registerAppender ()
{
    log4cplus::spi::AppenderFactoryRegistry & reg
        = log4cplus::spi::getAppenderFactoryRegistry ();
    LOG4CPLUS_REG_APPENDER (reg, MSTTSAppender);
}

} // namespace log4cplus

extern "C"
BOOL WINAPI DllMain(LOG4CPLUS_DLLMAIN_HINSTANCE,  // handle to DLL module
                    DWORD fdwReason,     // reason for calling function
                    LPVOID)  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH:
    {
        log4cplus::MSTTSAppender::registerAppender ();
        break;
    }

    case DLL_THREAD_ATTACH:
        break;

    case DLL_THREAD_DETACH:
        break;

    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}
<commit_msg>msttsappender.cxx: Simplify flags setting.<commit_after>// Module:  Log4cplus
// File:    msttsappender.cxx
// Created: 10/2012
// Author:  Vaclav Zeman
//
//
//  Copyright (C) 2012-2013, Vaclav Zeman. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modifica-
//  tion, are permitted provided that the following conditions are met:
//
//  1. Redistributions of  source code must  retain the above copyright  notice,
//     this list of conditions and the following disclaimer.
//
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <log4cplus/config.hxx>
#include <log4cplus/msttsappender.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/thread/syncprims.h>

#include <iomanip>
#include <sstream>

#include <sapi.h>

namespace log4cplus
{

namespace
{

static
void
loglog_win32_error (tchar const * msg, bool dothrow = false)
{
    DWORD err = GetLastError ();
    tostringstream oss;
    oss << LOG4CPLUS_TEXT ("MSTTSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
        << err << LOG4CPLUS_TEXT (" / 0x")
        << std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
        << err;
    helpers::getLogLog ().error (oss.str (), dothrow);
}

static
void
loglog_com_error (tchar const * msg, HRESULT hr)
{
    tostringstream oss;
    oss << LOG4CPLUS_TEXT ("MSTTSAppender: ") << msg << LOG4CPLUS_TEXT(": ")
        << hr << LOG4CPLUS_TEXT (" / 0x")
        << std::setw (8) << std::setfill (LOG4CPLUS_TEXT ('0')) << std::hex
        << hr;
    helpers::getLogLog ().error (oss.str ());
}

struct COMInitializer
{
    explicit COMInitializer (DWORD apartment_model = COINIT_APARTMENTTHREADED,
        HRESULT hr = S_OK)
        : uninit ((hr = CoInitializeEx (NULL, apartment_model)
            , hr == S_OK || hr == S_FALSE))
    { }

    ~COMInitializer ()
    {
        if (uninit)
            CoUninitialize ();
    }

    bool const uninit;
};

class SpeechObjectThread
    : public virtual log4cplus::thread::AbstractThread
{
public:
    SpeechObjectThread (ISpVoice * & ispvoice_ref)
        : ispvoice (ispvoice_ref)
    {
        terminate_ev = CreateEvent (0, true, false, 0);
        if (! terminate_ev)
            loglog_win32_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CreateEvent failed"),
                true);
    }

    ~SpeechObjectThread ()
    {
        if (! CloseHandle (terminate_ev))
            loglog_win32_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CloseHandle failed"));
    }

    virtual
    void
    run ()
    {
        COMInitializer com_init (COINIT_MULTITHREADED);

        HRESULT hr = CoCreateInstance (CLSID_SpVoice, NULL,
            CLSCTX_ALL, IID_ISpVoice, reinterpret_cast<void **>(&ispvoice));
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: CoCreateInstance(IID_ISpVoice) failed"),
                hr);

        init_ev.signal ();

        for (;;)
        {
            // wait for the event and for messages
            DWORD dwReturn = 0;
            hr = ::CoWaitForMultipleHandles (0, INFINITE, 1, &terminate_ev,
                &dwReturn);

            // this thread has been reawakened. Determine why
            // and handle appropriately.
            if (hr == S_OK && dwReturn == WAIT_OBJECT_0)
                // our event happened.
                break;
            else if (FAILED (hr))
                loglog_com_error (
                    LOG4CPLUS_TEXT ("SpeechObjectThread: CoWaitForMultipleHandles() failed"),
                    hr);
        }
    };

    void
    wait_init_done () const
    {
        init_ev.wait ();
    }

    void
    terminate () const
    {
        if (! SetEvent (terminate_ev))
            loglog_win32_error (LOG4CPLUS_TEXT ("SpeechObjectThread: SetEvent failed"), true);
    }

private:
    ISpVoice * & ispvoice;
    thread::ManualResetEvent init_ev;
    HANDLE terminate_ev;
};

} // namespace

struct MSTTSAppender::Data
{
    Data ()
        : ispvoice (0)
        , async (false)
        , speak_punc (false)
    { }

    ~Data ()
    {
        if (ispvoice)
            ispvoice->Release ();
    }

    helpers::SharedObjectPtr<SpeechObjectThread> speech_thread;
    ISpVoice * ispvoice;
    bool async;
    bool speak_punc;
};

MSTTSAppender::MSTTSAppender ()
    : Appender ()
    , data (new Data)
{
    init ();
}

MSTTSAppender::MSTTSAppender (helpers::Properties const & props)
    : Appender (props)
    , data (new Data)
{
    unsigned long volume = 0;
    bool has_volume = props.getULong (volume, LOG4CPLUS_TEXT ("Volume"));
    if (has_volume)
        volume = (std::min) (volume, 100ul);

    long rate = 0;
    bool has_rate = props.getLong (rate, LOG4CPLUS_TEXT ("Rate"));
    if (has_rate)
        rate = (std::max) (-10l, (std::min) (rate, 10l));

    bool async;
    async = props.getBool (async, LOG4CPLUS_TEXT ("Async")) && async;

    bool speak_punc;
    speak_punc = props.getBool (speak_punc, LOG4CPLUS_TEXT ("SpeakPunc"))
        && speak_punc;

    init (has_rate ? &rate : 0, has_volume ? &volume : 0, speak_punc, async);
}

MSTTSAppender::~MSTTSAppender ()
{
    destructorImpl ();
    delete data;
}

void
MSTTSAppender::init (long const * rate, unsigned long const * volume,
    bool speak_punc, bool async)
{
    data->speech_thread =
        helpers::SharedObjectPtr<SpeechObjectThread> (
            new SpeechObjectThread (data->ispvoice));
    data->speech_thread->start ();
    data->speech_thread->wait_init_done ();

    COMInitializer com_init;

    HRESULT hr = S_OK;

    if (rate)
    {
        hr = data->ispvoice->SetRate (*rate);
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: SetRate failed"), hr);
    }

    if (volume)
    {
        hr = data->ispvoice->SetVolume (static_cast<USHORT>(*volume));
        if (FAILED (hr))
            loglog_com_error (
                LOG4CPLUS_TEXT ("SpeechObjectThread: SetVolume failed"), hr);
    }

    data->async = async;
    data->speak_punc = speak_punc;
}

void
MSTTSAppender::close ()
{
    data->speech_thread->terminate ();
    data->speech_thread->join ();
}

void
MSTTSAppender::append (spi::InternalLoggingEvent const & ev)
{
    if (! data->ispvoice)
        return;

    // TODO: Expose log4cplus' internal TLS to use here.
    tostringstream oss;
    layout->formatAndAppend(oss, ev);

    DWORD flags = SPF_IS_NOT_XML;

    flags |= SPF_ASYNC * +data->async;
    flags |= SPF_NLP_SPEAK_PUNC * +data->speak_punc;

    COMInitializer com_init;
    HRESULT hr = data->ispvoice->Speak (
        helpers::towstring (oss.str ()).c_str (), flags, NULL);
    if (FAILED (hr))
        loglog_com_error (LOG4CPLUS_TEXT ("Speak failed"), hr);
}

void
MSTTSAppender::registerAppender ()
{
    log4cplus::spi::AppenderFactoryRegistry & reg
        = log4cplus::spi::getAppenderFactoryRegistry ();
    LOG4CPLUS_REG_APPENDER (reg, MSTTSAppender);
}

} // namespace log4cplus

extern "C"
BOOL WINAPI DllMain(LOG4CPLUS_DLLMAIN_HINSTANCE,  // handle to DLL module
                    DWORD fdwReason,     // reason for calling function
                    LPVOID)  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH:
    {
        log4cplus::MSTTSAppender::registerAppender ();
        break;
    }

    case DLL_THREAD_ATTACH:
        break;

    case DLL_THREAD_DETACH:
        break;

    case DLL_PROCESS_DETACH:
        break;
    }

    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -Xclang -verify
// This test verifies that we do not produce a warning when an iterator is derefed.

#include <vector>

class MyClass;

std::vector<MyClass*> vect(3);
for (auto it = vect.begin(); it != vect.end(); ++it) MyClass* ptr = *it;
 // expected-no-diagnostics
.q
<commit_msg>Add lambda test for null deref.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -Xclang -verify
// This test verifies that we do not produce a warning when
// - an iterator is derefed;
// - a lambda function is derefed.

#include <vector>

class MyClass;

std::vector<MyClass*> vect(3);
for (auto it = vect.begin(); it != vect.end(); ++it) MyClass* ptr = *it;
 // expected-no-diagnostics

auto lamb =[](int x){return x;};
*lamb;
 // expected-no-diagnostics

.q

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2010 Daniel Wiberg
 *
 * 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.
 */

#include "Painter.h"
#include "util/ScopedLock.h"

#include <iostream>

namespace canvas
{

   Painter::Painter(int width, int height, std::string const&  fileOrCode, bool isFile)
      : m_painterMutex(),
        m_logMutex(),
        m_width(width),
        m_height(height),
        m_fileOrCode(fileOrCode),
        m_isFile(isFile),
        m_script(0),
        m_context(0),
        m_callbackIndex(0),
        m_windowBinding(0),
        m_contextBinding(0)
   {
   }

   void Painter::start()
   {
      v8::HandleScope scope;

      // Create V8 context
      m_scriptTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
      v8::Local<v8::Context> jsContext = v8::Local<v8::Context>::New(v8::Context::New(0, m_scriptTemplate));

      // Create bindings
      m_windowBinding = new binding::Object<Painter>("Window");
      m_windowBinding->function("setInterval", &Painter::setInterval)
                     .function("clearInterval", &Painter::clearInterval)
                     .function("getContext", &Painter::getContext)
                     .function("log", &Painter::log);

      m_contextBinding = new binding::Object<Context>("Context");
      m_contextBinding->function("scale", &Context::scale)
                      .function("rotate", &Context::rotate)
                      .function("translate", &Context::translate)
                      .function("beginPath", &Context::beginPath)
                      .function("closePath", &Context::closePath)
                      .function("moveTo", &Context::moveTo)
                      .function("lineTo", &Context::lineTo)
                      .function("fillRect", &Context::fillRect)
                      .function("strokeRect", &Context::strokeRect);

      v8::Context::Scope contextScope(jsContext);

      // Inject the window object
      jsContext->Global()->Set(v8::String::New("window"), m_windowBinding->wrap(this));

      // Create graphics context
      m_context = new Context(m_width, m_height);

      // Create javascript object
      m_script = new Script(jsContext);
      if (m_isFile)
         m_script->load(m_fileOrCode);
      else
         m_script->runString(m_fileOrCode);
   }

   Painter::~Painter()
   {
      delete m_script;
      delete m_context;
   }

   void Painter::draw()
   {
      ScopedLock lock(m_painterMutex);

      // Call all registered callbacks
      v8::HandleScope scope;
      v8::Context::Scope contextScope(m_script->context());
      v8::TryCatch tryCatch;

      CallbackMap::iterator it = m_callbacks.begin();
      CallbackMap::iterator end = m_callbacks.end();

      for (; it != end; ++it)
      {
         Callback & callback = it->second;

         v8::Handle<v8::Value> result = callback.call();
         if (result.IsEmpty())
         {
            v8::String::Utf8Value error(tryCatch.Exception());
            std::cerr << "Script runtime error: " << *error << std::endl;
         }
      }
   }

   void Painter::copyImageTo(void * target)
   {
      ScopedLock lock(m_painterMutex);
      if (target && m_context)
         m_context->copyImageTo(target);
   }

   int Painter::setInterval(v8::Handle<v8::Function> const& function)
   {
      m_callbacks.insert(std::make_pair(++m_callbackIndex, Callback(function)));
      return m_callbackIndex;
   }

   void Painter::clearInterval(int index)
   {
      CallbackMap::iterator result = m_callbacks.find(index);
      if (result != m_callbacks.end())
         m_callbacks.erase(result);
   }

   v8::Handle<v8::Value> Painter::getContext(std::string const& type)
   {
      v8::HandleScope scope;
      if (type == "2d")
         return scope.Close(m_contextBinding->wrap(m_context));

      std::cerr << "Error: Requested wrong context type '" << type << "'" << std::endl;
      return v8::Undefined();
   }

   void Painter::log(std::string const& log)
   {
      ScopedLock lock(m_logMutex);

      m_history.push_back(log);

      // We only store a 1000 log entries
      if (m_history.size() > 1000)
         m_history.pop_front();

      //std::cerr << log << std::endl;
   }

   std::string Painter::lastLogEntry()
   {
      ScopedLock lock(m_logMutex);

      if (m_history.empty())
         return "";

      std::string log = m_history.front();
      m_history.pop_front();
      return log;
   }

}

<commit_msg>Added some attribute bindings to the context.<commit_after>/**
 * Copyright (c) 2010 Daniel Wiberg
 *
 * 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.
 */

#include "Painter.h"
#include "util/ScopedLock.h"

#include <iostream>

namespace canvas
{

   Painter::Painter(int width, int height, std::string const&  fileOrCode, bool isFile)
      : m_painterMutex(),
        m_logMutex(),
        m_width(width),
        m_height(height),
        m_fileOrCode(fileOrCode),
        m_isFile(isFile),
        m_script(0),
        m_context(0),
        m_callbackIndex(0),
        m_windowBinding(0),
        m_contextBinding(0)
   {
   }

   void Painter::start()
   {
      v8::HandleScope scope;

      // Create V8 context
      m_scriptTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
      v8::Local<v8::Context> jsContext = v8::Local<v8::Context>::New(v8::Context::New(0, m_scriptTemplate));

      // Create bindings
      m_windowBinding = new binding::Object<Painter>("Window");
      m_windowBinding->function("setInterval", &Painter::setInterval)
                      .function("clearInterval", &Painter::clearInterval)
                      .function("getContext", &Painter::getContext)
                      .function("log", &Painter::log);

      m_contextBinding = new binding::Object<Context>("Context");
      m_contextBinding->function("scale", &Context::scale)
                       .function("rotate", &Context::rotate)
                       .function("translate", &Context::translate)
                       .function("beginPath", &Context::beginPath)
                       .function("closePath", &Context::closePath)
                       .function("moveTo", &Context::moveTo)
                       .function("lineTo", &Context::lineTo)
                       .function("fillRect", &Context::fillRect)
                       .function("strokeRect", &Context::strokeRect)
                       .attribute("lineWidth", &Context::lineWidth, &Context::setLineWidth)
                       .attribute("lineCap", &Context::lineCap, &Context::setLineCap);

      v8::Context::Scope contextScope(jsContext);

      // Inject the window object
      jsContext->Global()->Set(v8::String::New("window"), m_windowBinding->wrap(this));

      // Create graphics context
      m_context = new Context(m_width, m_height);

      // Create javascript object
      m_script = new Script(jsContext);
      if (m_isFile)
         m_script->load(m_fileOrCode);
      else
         m_script->runString(m_fileOrCode);
   }

   Painter::~Painter()
   {
      delete m_script;
      delete m_context;
   }

   void Painter::draw()
   {
      ScopedLock lock(m_painterMutex);

      // Call all registered callbacks
      v8::HandleScope scope;
      v8::Context::Scope contextScope(m_script->context());
      v8::TryCatch tryCatch;

      CallbackMap::iterator it = m_callbacks.begin();
      CallbackMap::iterator end = m_callbacks.end();

      for (; it != end; ++it)
      {
         Callback & callback = it->second;

         v8::Handle<v8::Value> result = callback.call();
         if (result.IsEmpty())
         {
            v8::String::Utf8Value error(tryCatch.Exception());
            std::cerr << "Script runtime error: " << *error << std::endl;
         }
      }
   }

   void Painter::copyImageTo(void * target)
   {
      ScopedLock lock(m_painterMutex);
      if (target && m_context)
         m_context->copyImageTo(target);
   }

   int Painter::setInterval(v8::Handle<v8::Function> const& function)
   {
      m_callbacks.insert(std::make_pair(++m_callbackIndex, Callback(function)));
      return m_callbackIndex;
   }

   void Painter::clearInterval(int index)
   {
      CallbackMap::iterator result = m_callbacks.find(index);
      if (result != m_callbacks.end())
         m_callbacks.erase(result);
   }

   v8::Handle<v8::Value> Painter::getContext(std::string const& type)
   {
      v8::HandleScope scope;
      if (type == "2d")
         return scope.Close(m_contextBinding->wrap(m_context));

      std::cerr << "Error: Requested wrong context type '" << type << "'" << std::endl;
      return v8::Undefined();
   }

   void Painter::log(std::string const& log)
   {
      ScopedLock lock(m_logMutex);

      m_history.push_back(log);

      // We only store a 1000 log entries
      if (m_history.size() > 1000)
         m_history.pop_front();

      //std::cerr << log << std::endl;
   }

   std::string Painter::lastLogEntry()
   {
      ScopedLock lock(m_logMutex);

      if (m_history.empty())
         return "";

      std::string log = m_history.front();
      m_history.pop_front();
      return log;
   }

}

<|endoftext|>