<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: geometry.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef GEOMETRY_HPP
#define GEOMETRY_HPP

// mapnik
#include <mapnik/vertex_vector.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/geom_util.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mapnik {
    enum GeomType {
    	Point = 1,
    	LineString = 2,
    	Polygon = 3
    };

    template <typename T>
    class geometry : private boost::noncopyable
    {
    public:
        typedef T vertex_type;
        typedef typename vertex_type::type value_type;
    public:
        geometry () {}

        Envelope<double> envelope()
        {
            Envelope<double> result;
            double x,y;
	    rewind(0);
            for (unsigned i=0;i<num_points();++i)
            {
                vertex(&x,&y);
                if (i==0)
                {
                    result.init(x,y,x,y);
                }
                else
                {
                    result.expand_to_include(x,y);
                }
            }
            return result;
        }

        virtual int type() const=0;
        virtual bool hit_test(value_type x,value_type y, double tol) const=0;
        virtual void label_position(double *x, double *y) const=0;
        virtual void move_to(value_type x,value_type y)=0;
        virtual void line_to(value_type x,value_type y)=0;
        virtual unsigned num_points() const = 0;
        virtual unsigned vertex(double* x, double* y) const=0;
        virtual void rewind(unsigned) const=0;
        virtual void set_capacity(size_t size)=0;
        virtual ~geometry() {}
    };

   template <typename T>
   class point : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef typename geometry<T>::value_type value_type;
      private:
         vertex_type pt_;
      public:
         point() : geometry<T>() {}

         int type() const
         {
            return Point;
         }

         void label_position(double *x, double *y) const
         {
            *x = pt_.x;
            *y = pt_.y;
         }

         void move_to(value_type x,value_type y)
         {
            pt_.x = x;
            pt_.y = y;
         }

         void line_to(value_type ,value_type ) {}

         unsigned num_points() const
         {
            return 1;
         }

         unsigned vertex(double* x, double* y) const
         {
            *x = pt_.x;
            *y = pt_.y;
            return SEG_LINETO;
         }

         void rewind(unsigned ) const {}

         bool hit_test(value_type x,value_type y, double tol) const
         {
            return point_in_circle(pt_.x,pt_.y, x,y,tol);
         }

         void set_capacity(size_t) {}
         virtual ~point() {}
   };

   template <typename T, template <typename> class Container=vertex_vector2>
   class polygon : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef typename geometry_base::value_type value_type;
         typedef Container<vertex_type> container_type;
      private:
         container_type cont_;
         mutable unsigned itr_;
      public:
         polygon()
            : geometry_base(),
              itr_(0)
         {}

         int type() const
         {
            return Polygon;
         }

         void label_position(double *x, double *y) const
         {
            unsigned size = cont_.size();
            if (size < 3)
            {
               cont_.get_vertex(0,x,y);
               return;
            }

            double ai;
            double atmp = 0;
            double xtmp = 0;
            double ytmp = 0;
            double x0 =0;
            double y0 =0;
            double x1 =0;
            double y1 =0;

            unsigned i,j;
            for (i = size-1,j = 0; j < size; i = j, ++j)
            {
               cont_.get_vertex(i,&x0,&y0);
               cont_.get_vertex(j,&x1,&y1);
               ai = x0 * y1 - x1 * y0;
               atmp += ai;
               xtmp += (x1 + x0) * ai;
               ytmp += (y1 + y0) * ai;
            }
            if (atmp != 0)
            {
               *x = xtmp/(3*atmp);
               *y = ytmp /(3*atmp);
               return;
            }
            *x=x0;
            *y=y0;
         }

         void line_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_LINETO);
         }

         void move_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_MOVETO);
         }

         unsigned num_points() const
         {
            return cont_.size();
         }

         unsigned vertex(double* x, double* y) const
         {
            return cont_.get_vertex(itr_++,x,y);
         }

         void rewind(unsigned ) const
         {
            itr_=0;
         }

         bool hit_test(value_type x,value_type y, double) const
         {
            return point_inside_path(x,y,cont_.begin(),cont_.end());
         }

         void set_capacity(size_t size)
         {
            cont_.set_capacity(size);
         }
         virtual ~polygon() {}
   };

   template <typename T, template <typename> class Container=vertex_vector2>
   class line_string : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry_base::value_type value_type;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef Container<vertex_type> container_type;
      private:
         container_type cont_;
         mutable unsigned itr_;
      public:
         line_string()
            : geometry_base(),
              itr_(0)
         {}

         int type() const
         {
            return LineString;
         }
         void label_position(double *x, double *y) const
         {
            // calculate mid point on line string
            double x0=0;
            double y0=0;
            double x1=0;
            double y1=0;

            unsigned size = cont_.size();
            if (size == 1)
            {
               cont_.get_vertex(0,x,y);
            }
            else if (size == 2)
            {

               cont_.get_vertex(0,&x0,&y0);
               cont_.get_vertex(1,&x1,&y1);
               *x = 0.5 * (x1 + x0);
               *y = 0.5 * (y1 + y0);
            }
            else
            {
               double len=0.0;
               for (unsigned pos = 1; pos < size; ++pos)
               {
                  cont_.get_vertex(pos-1,&x0,&y0);
                  cont_.get_vertex(pos,&x1,&y1);
                  double dx = x1 - x0;
                  double dy = y1 - y0;
                  len += sqrt(dx * dx + dy * dy);
               }
               double midlen = 0.5 * len;
               double dist = 0.0;
               for (unsigned pos = 1; pos < size;++pos)
               {
                  cont_.get_vertex(pos-1,&x0,&y0);
                  cont_.get_vertex(pos,&x1,&y1);
                  double dx = x1 - x0;
                  double dy = y1 - y0;
                  double seg_len = sqrt(dx * dx + dy * dy);
                  if (( dist + seg_len) >= midlen)
                  {
                     double r = (midlen - dist)/seg_len;
                     *x = x0 + (x1 - x0) * r;
                     *y = y0 + (y1 - y0) * r;
                     break;
                  }
                  dist += seg_len;
               }
            }
         }
         void line_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_LINETO);
         }

         void move_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_MOVETO);
         }

         unsigned num_points() const
         {
            return cont_.size();
         }

         unsigned vertex(double* x, double* y) const
         {
            return cont_.get_vertex(itr_++,x,y);
         }

         void rewind(unsigned ) const
         {
            itr_=0;
         }

         bool hit_test(value_type x,value_type y, double tol) const
         {
            return point_on_path(x,y,cont_.begin(),cont_.end(),tol);
         }

         void set_capacity(size_t size)
         {
            cont_.set_capacity(size);
         }
         virtual ~line_string() {}
   };

   typedef point<vertex2d> point_impl;
   typedef line_string<vertex2d,vertex_vector2> line_string_impl;
   typedef polygon<vertex2d,vertex_vector2> polygon_impl;

   typedef geometry<vertex2d> geometry2d;
   typedef boost::shared_ptr<geometry2d> geometry_ptr;
   typedef boost::ptr_vector<geometry2d> geometry_containter;
}

#endif //GEOMETRY_HPP
<commit_msg>Improve numerical accuracy of calculations used for finding the polygon centroid. Otherwise the labels for small polygons might appear outside the boundary.<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: geometry.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef GEOMETRY_HPP
#define GEOMETRY_HPP

// mapnik
#include <mapnik/vertex_vector.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/geom_util.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mapnik {
    enum GeomType {
    	Point = 1,
    	LineString = 2,
    	Polygon = 3
    };

    template <typename T>
    class geometry : private boost::noncopyable
    {
    public:
        typedef T vertex_type;
        typedef typename vertex_type::type value_type;
    public:
        geometry () {}

        Envelope<double> envelope()
        {
            Envelope<double> result;
            double x,y;
	    rewind(0);
            for (unsigned i=0;i<num_points();++i)
            {
                vertex(&x,&y);
                if (i==0)
                {
                    result.init(x,y,x,y);
                }
                else
                {
                    result.expand_to_include(x,y);
                }
            }
            return result;
        }

        virtual int type() const=0;
        virtual bool hit_test(value_type x,value_type y, double tol) const=0;
        virtual void label_position(double *x, double *y) const=0;
        virtual void move_to(value_type x,value_type y)=0;
        virtual void line_to(value_type x,value_type y)=0;
        virtual unsigned num_points() const = 0;
        virtual unsigned vertex(double* x, double* y) const=0;
        virtual void rewind(unsigned) const=0;
        virtual void set_capacity(size_t size)=0;
        virtual ~geometry() {}
    };

   template <typename T>
   class point : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef typename geometry<T>::value_type value_type;
      private:
         vertex_type pt_;
      public:
         point() : geometry<T>() {}

         int type() const
         {
            return Point;
         }

         void label_position(double *x, double *y) const
         {
            *x = pt_.x;
            *y = pt_.y;
         }

         void move_to(value_type x,value_type y)
         {
            pt_.x = x;
            pt_.y = y;
         }

         void line_to(value_type ,value_type ) {}

         unsigned num_points() const
         {
            return 1;
         }

         unsigned vertex(double* x, double* y) const
         {
            *x = pt_.x;
            *y = pt_.y;
            return SEG_LINETO;
         }

         void rewind(unsigned ) const {}

         bool hit_test(value_type x,value_type y, double tol) const
         {
            return point_in_circle(pt_.x,pt_.y, x,y,tol);
         }

         void set_capacity(size_t) {}
         virtual ~point() {}
   };

   template <typename T, template <typename> class Container=vertex_vector2>
   class polygon : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef typename geometry_base::value_type value_type;
         typedef Container<vertex_type> container_type;
      private:
         container_type cont_;
         mutable unsigned itr_;
      public:
         polygon()
            : geometry_base(),
              itr_(0)
         {}

         int type() const
         {
            return Polygon;
         }

         void label_position(double *x, double *y) const
         {
            unsigned size = cont_.size();
            if (size < 3)
            {
               cont_.get_vertex(0,x,y);
               return;
            }

            double ai;
            double atmp = 0;
            double xtmp = 0;
            double ytmp = 0;
            double x0 =0;
            double y0 =0;
            double x1 =0;
            double y1 =0;
            double ox =0;
            double oy =0;

            unsigned i;

            // Use first point as origin to improve numerical accuracy
            cont_.get_vertex(0,&ox,&oy);

            for (i = 0; i < size-1; i++)
            {
               cont_.get_vertex(i,&x0,&y0);
               cont_.get_vertex(i+1,&x1,&y1);

               x0 -= ox; y0 -= oy;
               x1 -= ox; y1 -= oy;

               ai = x0 * y1 - x1 * y0;
               atmp += ai;
               xtmp += (x1 + x0) * ai;
               ytmp += (y1 + y0) * ai;
            }
            if (atmp != 0)
            {
               *x = (xtmp/(3*atmp)) + ox;
               *y = (ytmp/(3*atmp)) + oy;
               return;
            }
            *x=x0;
            *y=y0;
         }

         void line_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_LINETO);
         }

         void move_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_MOVETO);
         }

         unsigned num_points() const
         {
            return cont_.size();
         }

         unsigned vertex(double* x, double* y) const
         {
            return cont_.get_vertex(itr_++,x,y);
         }

         void rewind(unsigned ) const
         {
            itr_=0;
         }

         bool hit_test(value_type x,value_type y, double) const
         {
            return point_inside_path(x,y,cont_.begin(),cont_.end());
         }

         void set_capacity(size_t size)
         {
            cont_.set_capacity(size);
         }
         virtual ~polygon() {}
   };

   template <typename T, template <typename> class Container=vertex_vector2>
   class line_string : public geometry<T>
   {
         typedef geometry<T> geometry_base;
         typedef typename geometry_base::value_type value_type;
         typedef typename geometry<T>::vertex_type vertex_type;
         typedef Container<vertex_type> container_type;
      private:
         container_type cont_;
         mutable unsigned itr_;
      public:
         line_string()
            : geometry_base(),
              itr_(0)
         {}

         int type() const
         {
            return LineString;
         }
         void label_position(double *x, double *y) const
         {
            // calculate mid point on line string
            double x0=0;
            double y0=0;
            double x1=0;
            double y1=0;

            unsigned size = cont_.size();
            if (size == 1)
            {
               cont_.get_vertex(0,x,y);
            }
            else if (size == 2)
            {

               cont_.get_vertex(0,&x0,&y0);
               cont_.get_vertex(1,&x1,&y1);
               *x = 0.5 * (x1 + x0);
               *y = 0.5 * (y1 + y0);
            }
            else
            {
               double len=0.0;
               for (unsigned pos = 1; pos < size; ++pos)
               {
                  cont_.get_vertex(pos-1,&x0,&y0);
                  cont_.get_vertex(pos,&x1,&y1);
                  double dx = x1 - x0;
                  double dy = y1 - y0;
                  len += sqrt(dx * dx + dy * dy);
               }
               double midlen = 0.5 * len;
               double dist = 0.0;
               for (unsigned pos = 1; pos < size;++pos)
               {
                  cont_.get_vertex(pos-1,&x0,&y0);
                  cont_.get_vertex(pos,&x1,&y1);
                  double dx = x1 - x0;
                  double dy = y1 - y0;
                  double seg_len = sqrt(dx * dx + dy * dy);
                  if (( dist + seg_len) >= midlen)
                  {
                     double r = (midlen - dist)/seg_len;
                     *x = x0 + (x1 - x0) * r;
                     *y = y0 + (y1 - y0) * r;
                     break;
                  }
                  dist += seg_len;
               }
            }
         }
         void line_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_LINETO);
         }

         void move_to(value_type x,value_type y)
         {
            cont_.push_back(x,y,SEG_MOVETO);
         }

         unsigned num_points() const
         {
            return cont_.size();
         }

         unsigned vertex(double* x, double* y) const
         {
            return cont_.get_vertex(itr_++,x,y);
         }

         void rewind(unsigned ) const
         {
            itr_=0;
         }

         bool hit_test(value_type x,value_type y, double tol) const
         {
            return point_on_path(x,y,cont_.begin(),cont_.end(),tol);
         }

         void set_capacity(size_t size)
         {
            cont_.set_capacity(size);
         }
         virtual ~line_string() {}
   };

   typedef point<vertex2d> point_impl;
   typedef line_string<vertex2d,vertex_vector2> line_string_impl;
   typedef polygon<vertex2d,vertex_vector2> polygon_impl;

   typedef geometry<vertex2d> geometry2d;
   typedef boost::shared_ptr<geometry2d> geometry_ptr;
   typedef boost::ptr_vector<geometry2d> geometry_containter;
}

#endif //GEOMETRY_HPP
<|endoftext|>


<commit_before>/*
 * posix_semaphore.hpp
 *
 * MIT License
 *
 * Copyright (c) 2019 yohhoy
 *
 * 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.
 */
#ifndef POSIX_SEMAPHORE_HPP_
#define POSIX_SEMAPHORE_HPP_

#include <cassert>
#include <cstddef>
#include <chrono>
#include <system_error>
// POSIX semaphore
#include <semaphore.h>

/*
 * Semaphores in C++20 Standard Library
 *
 * - yamc::posix::counting_semaphore<least_max_value>
 * - yamc::posix::binary_semaphore
 *
 * This implementation use POSIX unnamed semaphore.
 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html
 */
namespace yamc {

namespace posix {

template <std::ptrdiff_t least_max_value = SEM_VALUE_MAX>
class counting_semaphore {
  ::sem_t sem_;

  void throw_errno(const char* what_arg)
  {
    throw std::system_error(std::error_code(errno, std::system_category()), what_arg);
  }

  bool do_try_acquirewait(const std::chrono::system_clock::time_point& tp)
  {
    using namespace std::chrono;
    // convert C++ system_clock to POSIX struct timespec
    struct ::timespec abs_timeout;
    abs_timeout.tv_sec = system_clock::to_time_t(tp);
    abs_timeout.tv_nsec = (long)(duration_cast<nanoseconds>(tp.time_since_epoch()).count() % 1000000000);

    errno = 0;
    if (::sem_timedwait(&sem_, abs_timeout) == 0) {
      return true;
    } else if (errno != ETIMEOUT) {
      throw_errno("sem_timedwait");
    }
    return false;
  }

public:
  static constexpr std::ptrdiff_t max() noexcept
  {
    static_assert(0 < least_max_value, "least_max_value shall be greater than zero");
    static_assert(least_max_value <= SEM_VALUE_MAX, "least_max_value shall be less than or equal to SEM_VALUE_MAX");
    return least_max_value;
  }

  /*constexpr*/ explicit counting_semaphore(std::ptrdiff_t desired)
  {
    assert(0 <= desired && desired <= max());
    ::sem_init(&sem_, 0, (unsigned int)desired);
    // counting_semaphore constructor throws nothing.
  }

  ~counting_semaphore()
  {
    ::sem_destroy(&sem_);
  }

  counting_semaphore(const counting_semaphore&) = delete;
  counting_semaphore& operator=(const counting_semaphore&) = delete;

  void release(std::ptrdiff_t update = 1)
  {
    errno = 0;
    while (0 < update--) {
      if (::sem_post(&sem_) != 0) {
        throw_errno("sem_post");
      }
    }
  }

  void acquire()
  {
    errno = 0;
    if (::sem_wait(&sem_) != 0) {
      throw_errno("sem_wait");
    }
  }

  bool try_acquire() noexcept
  {
    return ::sem_trywait(&sem_);
  }

  template<class Rep, class Period>
  bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time)
  {
    // C++ Standard says '_for'-suffixed timeout function shall use steady clock,
    // but we use std::chorno::system_clock which may or may not be steady.
    const auto tp = std::chrono::system_clock::now() + rel_time;
    return do_try_acquirewait(tp);
  }

  template<class Clock, class Duration>
  bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time)
  {
    return do_try_acquirewait(abs_time);
  }
};

using binary_semaphore = counting_semaphore<1>;

} // namespace posix
} // namespace yamc

#endif
<commit_msg>fix compile error at posix_semaphore.hpp<commit_after>/*
 * posix_semaphore.hpp
 *
 * MIT License
 *
 * Copyright (c) 2019 yohhoy
 *
 * 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.
 */
#ifndef POSIX_SEMAPHORE_HPP_
#define POSIX_SEMAPHORE_HPP_

#include <cassert>
#include <cstddef>
#include <chrono>
#include <system_error>
// POSIX semaphore
#include <limits.h>
#include <semaphore.h>

/*
 * Semaphores in C++20 Standard Library
 *
 * - yamc::posix::counting_semaphore<least_max_value>
 * - yamc::posix::binary_semaphore
 *
 * This implementation use POSIX unnamed semaphore.
 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html
 */
namespace yamc {

namespace posix {

template <std::ptrdiff_t least_max_value = SEM_VALUE_MAX>
class counting_semaphore {
  ::sem_t sem_;

  void throw_errno(const char* what_arg)
  {
    throw std::system_error(std::error_code(errno, std::system_category()), what_arg);
  }

  bool do_try_acquirewait(const std::chrono::system_clock::time_point& tp)
  {
    using namespace std::chrono;
    // convert C++ system_clock to POSIX struct timespec
    struct ::timespec abs_timeout;
    abs_timeout.tv_sec = system_clock::to_time_t(tp);
    abs_timeout.tv_nsec = (long)(duration_cast<nanoseconds>(tp.time_since_epoch()).count() % 1000000000);

    errno = 0;
    if (::sem_timedwait(&sem_, &abs_timeout) == 0) {
      return true;
    } else if (errno != ETIMEDOUT) {
      throw_errno("sem_timedwait");
    }
    return false;
  }

public:
  static constexpr std::ptrdiff_t max() noexcept
  {
    static_assert(0 < least_max_value, "least_max_value shall be greater than zero");
    static_assert(least_max_value <= SEM_VALUE_MAX, "least_max_value shall be less than or equal to SEM_VALUE_MAX");
    return least_max_value;
  }

  /*constexpr*/ explicit counting_semaphore(std::ptrdiff_t desired)
  {
    assert(0 <= desired && desired <= max());
    ::sem_init(&sem_, 0, (unsigned int)desired);
    // counting_semaphore constructor throws nothing.
  }

  ~counting_semaphore()
  {
    ::sem_destroy(&sem_);
  }

  counting_semaphore(const counting_semaphore&) = delete;
  counting_semaphore& operator=(const counting_semaphore&) = delete;

  void release(std::ptrdiff_t update = 1)
  {
    errno = 0;
    while (0 < update--) {
      if (::sem_post(&sem_) != 0) {
        throw_errno("sem_post");
      }
    }
  }

  void acquire()
  {
    errno = 0;
    if (::sem_wait(&sem_) != 0) {
      throw_errno("sem_wait");
    }
  }

  bool try_acquire() noexcept
  {
    return (::sem_trywait(&sem_) == 0);
  }

  template<class Rep, class Period>
  bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time)
  {
    // C++ Standard says '_for'-suffixed timeout function shall use steady clock,
    // but we use std::chorno::system_clock which may or may not be steady.
    const auto tp = std::chrono::system_clock::now() + rel_time;
    return do_try_acquirewait(tp);
  }

  template<class Clock, class Duration>
  bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time)
  {
    return do_try_acquirewait(abs_time);
  }
};

using binary_semaphore = counting_semaphore<1>;

} // namespace posix
} // namespace yamc

#endif
<|endoftext|>


<commit_before>#pragma once

#include "simlib/string_view.hh"

template <size_t N>
class InplaceBuff;

// This type should NOT be returned from a function call
class FilePath {
    const char* str_;
    size_t size_;

public:
    FilePath(const FilePath&) noexcept = default;
    FilePath(FilePath&&) noexcept = default;

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(const char* str) noexcept
    : str_(str)
    , size_(std::char_traits<char>::length(str)) {}

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(const CStringView& str) noexcept
    : str_(str.c_str())
    , size_(str.size()) {}

    // NOLINTNEXTLINE(google-explicit-constructor)
    FilePath(const std::string& str) noexcept
    : str_(str.c_str())
    , size_(str.size()) {}

    template <size_t N>
    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(InplaceBuff<N>& str) noexcept
    : str_(str.to_cstr().data())
    , size_(str.size) {}

    template <size_t N>
    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(InplaceBuff<N>&& str) noexcept
    : str_(str.to_cstr().data())
    , size_(str.size) {}

    constexpr FilePath& operator=(const FilePath&) noexcept = delete;
    constexpr FilePath& operator=(FilePath&&) noexcept = delete;
    // NOLINTNEXTLINE(misc-unconventional-assign-operator)
    FilePath& operator=(FilePath&) noexcept = default;

    constexpr FilePath& operator=(const char* str) noexcept {
        str_ = str;
        size_ = std::char_traits<char>::length(str);
        return *this;
    }

    constexpr FilePath& operator=(CStringView& str) noexcept {
        str_ = str.c_str();
        size_ = str.size();
        return *this;
    }

    FilePath& operator=(std::string& str) noexcept {
        str_ = str.c_str();
        size_ = str.size();
        return *this;
    }

    template <size_t N>
    constexpr FilePath& operator=(InplaceBuff<N>& str) noexcept {
        str_ = str.to_cstr().data();
        size_ = str.size;
        return *this;
    }

    ~FilePath() = default;

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr operator const char*() const noexcept { return str_; }

    [[nodiscard]] constexpr CStringView to_cstr() const noexcept { return {str_, size_}; }

    [[nodiscard]] std::string to_str() const noexcept { return {str_, size_}; }

    [[nodiscard]] constexpr const char* data() const noexcept { return str_; }

    [[nodiscard]] constexpr size_t size() const noexcept { return size_; }
};
<commit_msg>file_path.hh: added conversion from StaticCStringBuff<commit_after>#pragma once

#include "simlib/string_view.hh"

template <size_t N>
class StaticCStringBuff;

template <size_t N>
class InplaceBuff;

// This type should NOT be returned from a function call
class FilePath {
    const char* str_;
    size_t size_;

public:
    FilePath(const FilePath&) noexcept = default;
    FilePath(FilePath&&) noexcept = default;

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(const char* str) noexcept
    : str_(str)
    , size_(std::char_traits<char>::length(str)) {}

    template<size_t N>
    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(const StaticCStringBuff<N>& str) noexcept
    : str_(str.data())
    , size_(str.size()) {}

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(const CStringView& str) noexcept
    : str_(str.c_str())
    , size_(str.size()) {}

    // NOLINTNEXTLINE(google-explicit-constructor)
    FilePath(const std::string& str) noexcept
    : str_(str.c_str())
    , size_(str.size()) {}

    template <size_t N>
    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(InplaceBuff<N>& str) noexcept
    : str_(str.to_cstr().data())
    , size_(str.size) {}

    template <size_t N>
    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr FilePath(InplaceBuff<N>&& str) noexcept
    : str_(str.to_cstr().data())
    , size_(str.size) {}

    constexpr FilePath& operator=(const FilePath&) noexcept = delete;
    constexpr FilePath& operator=(FilePath&&) noexcept = delete;
    // NOLINTNEXTLINE(misc-unconventional-assign-operator)
    FilePath& operator=(FilePath&) noexcept = default;

    constexpr FilePath& operator=(const char* str) noexcept {
        str_ = str;
        size_ = std::char_traits<char>::length(str);
        return *this;
    }

    constexpr FilePath& operator=(CStringView& str) noexcept {
        str_ = str.c_str();
        size_ = str.size();
        return *this;
    }

    FilePath& operator=(std::string& str) noexcept {
        str_ = str.c_str();
        size_ = str.size();
        return *this;
    }

    template <size_t N>
    constexpr FilePath& operator=(InplaceBuff<N>& str) noexcept {
        str_ = str.to_cstr().data();
        size_ = str.size;
        return *this;
    }

    ~FilePath() = default;

    // NOLINTNEXTLINE(google-explicit-constructor)
    constexpr operator const char*() const noexcept { return str_; }

    [[nodiscard]] constexpr CStringView to_cstr() const noexcept { return {str_, size_}; }

    [[nodiscard]] std::string to_str() const noexcept { return {str_, size_}; }

    [[nodiscard]] constexpr const char* data() const noexcept { return str_; }

    [[nodiscard]] constexpr size_t size() const noexcept { return size_; }
};
<|endoftext|>


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

#include "ftrace_procfs.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <fstream>
#include <sstream>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/base/utils.h"

namespace perfetto {
namespace {

// Reading /trace produces human readable trace output.
// Writing to this file clears all trace buffers for all CPUS.

// Writing to /trace_marker file injects an event into the trace buffer.

// Reading /tracing_on returns 1/0 if tracing is enabled/disabled.
// Writing 1/0 to this file enables/disables tracing.
// Disabling tracing with this file prevents further writes but
// does not clear the buffer.

char ReadOneCharFromFile(const std::string& path) {
  base::ScopedFile fd(open(path.c_str(), O_RDONLY));
  PERFETTO_CHECK(fd);
  char result = '\0';
  ssize_t bytes = PERFETTO_EINTR(read(fd.get(), &result, 1));
  PERFETTO_CHECK(bytes == 1 || bytes == -1);
  return result;
}

std::string ReadFileIntoString(std::string path) {
  std::ifstream fin(path, std::ios::in);
  if (!fin) {
    PERFETTO_DLOG("Could not read '%s'", path.c_str());
    return "";
  }

  std::string str;
  // You can't seek or stat the procfs files on Android.
  // The vast majority (884/886) of format files are under 4k.
  str.reserve(4096);
  str.assign(std::istreambuf_iterator<char>(fin),
             std::istreambuf_iterator<char>());

  return str;
}

}  // namespace

FtraceProcfs::FtraceProcfs(const std::string& root) : root_(root) {}
FtraceProcfs::~FtraceProcfs() = default;

bool FtraceProcfs::EnableEvent(const std::string& group,
                               const std::string& name) {
  std::string path = root_ + "events/" + group + "/" + name + "/enable";
  return WriteToFile(path, "1");
}

bool FtraceProcfs::DisableEvent(const std::string& group,
                                const std::string& name) {
  std::string path = root_ + "events/" + group + "/" + name + "/enable";
  return WriteToFile(path, "0");
}

bool FtraceProcfs::DisableAllEvents() {
  std::string path = root_ + "events/enable";
  return WriteToFile(path, "0");
}

std::string FtraceProcfs::ReadEventFormat(const std::string& group,
                                          const std::string& name) const {
  std::string path = root_ + "events/" + group + "/" + name + "/format";
  return ReadFileIntoString(path);
}

std::string FtraceProcfs::ReadAvailableEvents() const {
  std::string path = root_ + "available_events";
  return ReadFileIntoString(path);
}

size_t FtraceProcfs::NumberOfCpus() const {
  static size_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
  return num_cpus;
}

void FtraceProcfs::ClearTrace() {
  std::string path = root_ + "trace";
  base::ScopedFile fd(open(path.c_str(), O_WRONLY | O_TRUNC));
  PERFETTO_CHECK(fd);  // Could not clear.
}

bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
  std::string path = root_ + "trace_marker";
  return WriteToFile(path, str);
}

bool FtraceProcfs::EnableTracing() {
  std::string path = root_ + "tracing_on";
  return WriteToFile(path, "1");
}

bool FtraceProcfs::DisableTracing() {
  std::string path = root_ + "tracing_on";
  return WriteToFile(path, "0");
}

bool FtraceProcfs::IsTracingEnabled() {
  std::string path = root_ + "tracing_on";
  return ReadOneCharFromFile(path) == '1';
}

bool FtraceProcfs::WriteToFile(const std::string& path,
                               const std::string& str) {
  base::ScopedFile fd(open(path.c_str(), O_WRONLY));
  if (!fd)
    return false;
  ssize_t written = PERFETTO_EINTR(write(fd.get(), str.c_str(), str.length()));
  ssize_t length = static_cast<ssize_t>(str.length());
  // This should either fail or write fully.
  PERFETTO_CHECK(written == length || written == -1);
  return written == length;
}

base::ScopedFile FtraceProcfs::OpenPipeForCpu(size_t cpu) {
  std::string path =
      root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
  return base::ScopedFile(open(path.c_str(), O_RDONLY | O_NONBLOCK));
}

}  // namespace perfetto
<commit_msg>Open all ftrace_reader files with O_CLOEXEC. am: 74a9322960 am: bd17b8a45c<commit_after>/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ftrace_procfs.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <fstream>
#include <sstream>
#include <string>

#include "perfetto/base/logging.h"
#include "perfetto/base/utils.h"

namespace perfetto {
namespace {

// Reading /trace produces human readable trace output.
// Writing to this file clears all trace buffers for all CPUS.

// Writing to /trace_marker file injects an event into the trace buffer.

// Reading /tracing_on returns 1/0 if tracing is enabled/disabled.
// Writing 1/0 to this file enables/disables tracing.
// Disabling tracing with this file prevents further writes but
// does not clear the buffer.

char ReadOneCharFromFile(const std::string& path) {
  base::ScopedFile fd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
  PERFETTO_CHECK(fd);
  char result = '\0';
  ssize_t bytes = PERFETTO_EINTR(read(fd.get(), &result, 1));
  PERFETTO_CHECK(bytes == 1 || bytes == -1);
  return result;
}

std::string ReadFileIntoString(std::string path) {
  std::ifstream fin(path, std::ios::in);
  if (!fin) {
    PERFETTO_DLOG("Could not read '%s'", path.c_str());
    return "";
  }

  std::string str;
  // You can't seek or stat the procfs files on Android.
  // The vast majority (884/886) of format files are under 4k.
  str.reserve(4096);
  str.assign(std::istreambuf_iterator<char>(fin),
             std::istreambuf_iterator<char>());

  return str;
}

}  // namespace

FtraceProcfs::FtraceProcfs(const std::string& root) : root_(root) {}
FtraceProcfs::~FtraceProcfs() = default;

bool FtraceProcfs::EnableEvent(const std::string& group,
                               const std::string& name) {
  std::string path = root_ + "events/" + group + "/" + name + "/enable";
  return WriteToFile(path, "1");
}

bool FtraceProcfs::DisableEvent(const std::string& group,
                                const std::string& name) {
  std::string path = root_ + "events/" + group + "/" + name + "/enable";
  return WriteToFile(path, "0");
}

bool FtraceProcfs::DisableAllEvents() {
  std::string path = root_ + "events/enable";
  return WriteToFile(path, "0");
}

std::string FtraceProcfs::ReadEventFormat(const std::string& group,
                                          const std::string& name) const {
  std::string path = root_ + "events/" + group + "/" + name + "/format";
  return ReadFileIntoString(path);
}

std::string FtraceProcfs::ReadAvailableEvents() const {
  std::string path = root_ + "available_events";
  return ReadFileIntoString(path);
}

size_t FtraceProcfs::NumberOfCpus() const {
  static size_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
  return num_cpus;
}

void FtraceProcfs::ClearTrace() {
  std::string path = root_ + "trace";
  base::ScopedFile fd(open(path.c_str(), O_WRONLY | O_TRUNC | O_CLOEXEC));
  PERFETTO_CHECK(fd);  // Could not clear.
}

bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
  std::string path = root_ + "trace_marker";
  return WriteToFile(path, str);
}

bool FtraceProcfs::EnableTracing() {
  std::string path = root_ + "tracing_on";
  return WriteToFile(path, "1");
}

bool FtraceProcfs::DisableTracing() {
  std::string path = root_ + "tracing_on";
  return WriteToFile(path, "0");
}

bool FtraceProcfs::IsTracingEnabled() {
  std::string path = root_ + "tracing_on";
  return ReadOneCharFromFile(path) == '1';
}

bool FtraceProcfs::WriteToFile(const std::string& path,
                               const std::string& str) {
  base::ScopedFile fd(open(path.c_str(), O_WRONLY | O_CLOEXEC));
  if (!fd)
    return false;
  ssize_t written = PERFETTO_EINTR(write(fd.get(), str.c_str(), str.length()));
  ssize_t length = static_cast<ssize_t>(str.length());
  // This should either fail or write fully.
  PERFETTO_CHECK(written == length || written == -1);
  return written == length;
}

base::ScopedFile FtraceProcfs::OpenPipeForCpu(size_t cpu) {
  std::string path =
      root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace_pipe_raw";
  return base::ScopedFile(
      open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
}

}  // namespace perfetto
<|endoftext|>


<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 2013-2014 by Ullrich Koethe                  */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_THREADING_HXX
#define VIGRA_THREADING_HXX

/* Compatibility header to import threading-related functionality from boost
   when the compiler doesn't yet support C++11.
*/

    // ignore all threading if VIGRA_SINGLE_THREADED is defined
#ifndef VIGRA_SINGLE_THREADED

#ifndef VIGRA_NO_STD_THREADING
# if defined(__clang__)
#  if (!__has_include(<thread>) || !__has_include(<mutex>) || !__has_include(<atomic>))
#    define VIGRA_NO_STD_THREADING
#  endif
# else
#  if defined(__GNUC__) && (!defined(_GLIBCXX_HAS_GTHREADS) || !defined(_GLIBCXX_USE_C99_STDINT_TR1))
#    define VIGRA_NO_STD_THREADING
#  endif
# endif

# if defined(_MSC_VER) && _MSC_VER <= 1600
#  define VIGRA_NO_STD_THREADING
# endif
#endif

#ifdef USE_BOOST_THREAD
#  include <boost/thread.hpp>
#  if BOOST_VERSION >= 105300
#    include <boost/atomic.hpp>
#    define VIGRA_HAS_ATOMIC 1
#  endif
#  define VIGRA_THREADING_NAMESPACE boost
#elif defined(VIGRA_NO_STD_THREADING)
#  error "Your compiler does not support std::thread. If the boost libraries are available, consider running cmake with -DWITH_BOOST_THREAD=1"
#else
#  include <thread>
#  include <mutex>
// #  include <shared_mutex>  // C++14
#  include <atomic>
#  define VIGRA_HAS_ATOMIC 1
#  define VIGRA_THREADING_NAMESPACE std
#endif

#if defined(_MSC_VER) && !defined(VIGRA_HAS_ATOMIC)
#  include "windows.h"
#endif

namespace vigra { namespace threading {

// contents of <thread>

using VIGRA_THREADING_NAMESPACE::thread;

namespace this_thread {

using VIGRA_THREADING_NAMESPACE::this_thread::yield;
using VIGRA_THREADING_NAMESPACE::this_thread::get_id;
using VIGRA_THREADING_NAMESPACE::this_thread::sleep_for;
using VIGRA_THREADING_NAMESPACE::this_thread::sleep_until;

} // namespace this_thread

// contents of <mutex>

using VIGRA_THREADING_NAMESPACE::mutex;
using VIGRA_THREADING_NAMESPACE::timed_mutex;
using VIGRA_THREADING_NAMESPACE::recursive_mutex;
using VIGRA_THREADING_NAMESPACE::recursive_timed_mutex;

using VIGRA_THREADING_NAMESPACE::lock_guard;
using VIGRA_THREADING_NAMESPACE::unique_lock;

using VIGRA_THREADING_NAMESPACE::defer_lock_t;
using VIGRA_THREADING_NAMESPACE::try_to_lock_t;
using VIGRA_THREADING_NAMESPACE::adopt_lock_t;

using VIGRA_THREADING_NAMESPACE::defer_lock;
using VIGRA_THREADING_NAMESPACE::try_to_lock;
using VIGRA_THREADING_NAMESPACE::adopt_lock;

using VIGRA_THREADING_NAMESPACE::try_lock;
using VIGRA_THREADING_NAMESPACE::lock;

using VIGRA_THREADING_NAMESPACE::once_flag;
using VIGRA_THREADING_NAMESPACE::call_once;

// contents of <shared_mutex>

// using VIGRA_THREADING_NAMESPACE::shared_mutex;   // C++14
// using VIGRA_THREADING_NAMESPACE::shared_lock;  // C++14

#ifdef VIGRA_HAS_ATOMIC

// contents of <atomic>

using VIGRA_THREADING_NAMESPACE::atomic_flag;
using VIGRA_THREADING_NAMESPACE::atomic;

using VIGRA_THREADING_NAMESPACE::atomic_char;
using VIGRA_THREADING_NAMESPACE::atomic_schar;
using VIGRA_THREADING_NAMESPACE::atomic_uchar;
using VIGRA_THREADING_NAMESPACE::atomic_short;
using VIGRA_THREADING_NAMESPACE::atomic_ushort;
using VIGRA_THREADING_NAMESPACE::atomic_int;
using VIGRA_THREADING_NAMESPACE::atomic_uint;
using VIGRA_THREADING_NAMESPACE::atomic_long;
using VIGRA_THREADING_NAMESPACE::atomic_ulong;
using VIGRA_THREADING_NAMESPACE::atomic_llong;
using VIGRA_THREADING_NAMESPACE::atomic_ullong;
// using VIGRA_THREADING_NAMESPACE::atomic_char16_t; // not in boost
// using VIGRA_THREADING_NAMESPACE::atomic_char32_t; // not in boost
using VIGRA_THREADING_NAMESPACE::atomic_wchar_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least8_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least8_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least16_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least16_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least32_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least32_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least64_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least64_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast8_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast8_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast16_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast16_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast32_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast32_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast64_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast64_t;
using VIGRA_THREADING_NAMESPACE::atomic_intptr_t;
using VIGRA_THREADING_NAMESPACE::atomic_uintptr_t;
using VIGRA_THREADING_NAMESPACE::atomic_size_t;
using VIGRA_THREADING_NAMESPACE::atomic_ptrdiff_t;
using VIGRA_THREADING_NAMESPACE::atomic_intmax_t;
using VIGRA_THREADING_NAMESPACE::atomic_uintmax_t;

using VIGRA_THREADING_NAMESPACE::memory_order;
using VIGRA_THREADING_NAMESPACE::memory_order_relaxed;
using VIGRA_THREADING_NAMESPACE::memory_order_release;
using VIGRA_THREADING_NAMESPACE::memory_order_acquire;
using VIGRA_THREADING_NAMESPACE::memory_order_consume;
using VIGRA_THREADING_NAMESPACE::memory_order_acq_rel;
using VIGRA_THREADING_NAMESPACE::memory_order_seq_cst;

using VIGRA_THREADING_NAMESPACE::atomic_thread_fence;
using VIGRA_THREADING_NAMESPACE::atomic_signal_fence;

// using VIGRA_THREADING_NAMESPACE::atomic_is_lock_free;
// using VIGRA_THREADING_NAMESPACE::atomic_storeatomic_store_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_loadatomic_load_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_exchangeatomic_exchange_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_addatomic_fetch_add_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_subatomic_fetch_sub_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_andatomic_fetch_and_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_oratomic_fetch_or_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_xoratomic_fetch_xor_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_flag_test_and_setatomic_flag_test_and_set_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_flag_clearatomic_flag_clear_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_init;
// using VIGRA_THREADING_NAMESPACE::kill_dependency;

#else  // VIGRA_HAS_ATOMIC not defined

enum memory_order {
    memory_order_relaxed,
    memory_order_release,
    memory_order_acquire,
    memory_order_consume,
    memory_order_acq_rel,
    memory_order_seq_cst
};

#ifdef _MSC_VER

template <int SIZE=4>
struct atomic_long_impl
{
    typedef LONG value_type;

    static long load(value_type const & val)
    {
        long res = val;
        MemoryBarrier();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        MemoryBarrier();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return InterlockedExchangeAdd(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return InterlockedExchangeAdd(&dest, -val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = InterlockedCompareExchange(&dest, new_val, old_val);
        return check_val == old_val;
    }
};

template <>
struct atomic_long_impl<8>
{
    typedef LONGLONG value_type;

    static long load(value_type const & val)
    {
        long res = val;
        MemoryBarrier();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        MemoryBarrier();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return InterlockedExchangeAdd64(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return InterlockedExchangeAdd64(&dest, -val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = InterlockedCompareExchange64(&dest, new_val, old_val);
        return check_val == old_val;
    }
};

#else

template <int SIZE=4>
struct atomic_long_impl
{
    typedef long value_type;

    static long load(value_type const & val)
    {
        long res = val;
        __sync_synchronize();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        __sync_synchronize();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return __sync_fetch_and_add(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return __sync_fetch_and_sub(&dest, val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = __sync_val_compare_and_swap(&dest, old_val, new_val);
        return check_val == old_val;
    }
};

#endif // _MSC_VER

struct atomic_long
{
    typedef atomic_long_impl<sizeof(long)>::value_type value_type;

    atomic_long(long v = 0)
    : value_(v)
    {}

    atomic_long & operator=(long val)
    {
        store(val);
        return *this;
    }

    long load(memory_order = memory_order_seq_cst) const
    {
        return atomic_long_impl<sizeof(long)>::load(value_);
    }

    void store(long v, memory_order = memory_order_seq_cst)
    {
        atomic_long_impl<sizeof(long)>::store(value_, v);
    }

    long fetch_add(long v, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::add(value_, v);
    }

    long fetch_sub(long v, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::sub(value_, v);
    }

    bool compare_exchange_strong(long & old_val, long new_val, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
    }

    bool compare_exchange_weak(long & old_val, long new_val, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
    }

    value_type value_;
};

#endif // VIGRA_HAS_ATOMIC

}} // namespace vigra::threading

#undef VIGRA_THREADING_NAMESPACE

#endif // not VIGRA_SINGLE_THREADED

#endif // VIGRA_THREADING_HXX
<commit_msg>threading.hxx: correctly deal with GCC 4.6/4.7<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 2013-2014 by Ullrich Koethe                  */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_THREADING_HXX
#define VIGRA_THREADING_HXX

/* Compatibility header to import threading-related functionality from boost
   when the compiler doesn't yet support C++11.
*/

    // ignore all threading if VIGRA_SINGLE_THREADED is defined
#ifndef VIGRA_SINGLE_THREADED

#ifndef VIGRA_NO_STD_THREADING
# if defined(__clang__)
#  if (!__has_include(<thread>) || !__has_include(<mutex>) || !__has_include(<atomic>))
#    define VIGRA_NO_STD_THREADING
#  endif
# else
#  if defined(__GNUC__) && (!defined(_GLIBCXX_HAS_GTHREADS) || !defined(_GLIBCXX_USE_C99_STDINT_TR1) || !defined(_GLIBCXX_USE_SCHED_YIELD))
#    define VIGRA_NO_STD_THREADING
#  endif
# endif

# if defined(_MSC_VER) && _MSC_VER <= 1600
#  define VIGRA_NO_STD_THREADING
# endif
#endif

#ifdef USE_BOOST_THREAD
#  include <boost/thread.hpp>
#  if BOOST_VERSION >= 105300
#    include <boost/atomic.hpp>
#    define VIGRA_HAS_ATOMIC 1
#  endif
#  define VIGRA_THREADING_NAMESPACE boost
#elif defined(VIGRA_NO_STD_THREADING)
#  error "Your compiler does not support std::thread. If the boost libraries are available, consider running cmake with -DWITH_BOOST_THREAD=1"
#else
#  include <thread>
#  include <mutex>
// #  include <shared_mutex>  // C++14
#  include <atomic>
#  define VIGRA_HAS_ATOMIC 1
#  define VIGRA_THREADING_NAMESPACE std
#endif

#if defined(_MSC_VER) && !defined(VIGRA_HAS_ATOMIC)
#  include "windows.h"
#endif

namespace vigra { namespace threading {

// contents of <thread>

using VIGRA_THREADING_NAMESPACE::thread;

namespace this_thread {

using VIGRA_THREADING_NAMESPACE::this_thread::yield;
using VIGRA_THREADING_NAMESPACE::this_thread::get_id;
using VIGRA_THREADING_NAMESPACE::this_thread::sleep_for;
using VIGRA_THREADING_NAMESPACE::this_thread::sleep_until;

} // namespace this_thread

// contents of <mutex>

using VIGRA_THREADING_NAMESPACE::mutex;
using VIGRA_THREADING_NAMESPACE::timed_mutex;
using VIGRA_THREADING_NAMESPACE::recursive_mutex;
using VIGRA_THREADING_NAMESPACE::recursive_timed_mutex;

using VIGRA_THREADING_NAMESPACE::lock_guard;
using VIGRA_THREADING_NAMESPACE::unique_lock;

using VIGRA_THREADING_NAMESPACE::defer_lock_t;
using VIGRA_THREADING_NAMESPACE::try_to_lock_t;
using VIGRA_THREADING_NAMESPACE::adopt_lock_t;

using VIGRA_THREADING_NAMESPACE::defer_lock;
using VIGRA_THREADING_NAMESPACE::try_to_lock;
using VIGRA_THREADING_NAMESPACE::adopt_lock;

using VIGRA_THREADING_NAMESPACE::try_lock;
using VIGRA_THREADING_NAMESPACE::lock;

using VIGRA_THREADING_NAMESPACE::once_flag;
using VIGRA_THREADING_NAMESPACE::call_once;

// contents of <shared_mutex>

// using VIGRA_THREADING_NAMESPACE::shared_mutex;   // C++14
// using VIGRA_THREADING_NAMESPACE::shared_lock;  // C++14

#ifdef VIGRA_HAS_ATOMIC

// contents of <atomic>

using VIGRA_THREADING_NAMESPACE::atomic_flag;
using VIGRA_THREADING_NAMESPACE::atomic;

using VIGRA_THREADING_NAMESPACE::atomic_char;
using VIGRA_THREADING_NAMESPACE::atomic_schar;
using VIGRA_THREADING_NAMESPACE::atomic_uchar;
using VIGRA_THREADING_NAMESPACE::atomic_short;
using VIGRA_THREADING_NAMESPACE::atomic_ushort;
using VIGRA_THREADING_NAMESPACE::atomic_int;
using VIGRA_THREADING_NAMESPACE::atomic_uint;
using VIGRA_THREADING_NAMESPACE::atomic_long;
using VIGRA_THREADING_NAMESPACE::atomic_ulong;
using VIGRA_THREADING_NAMESPACE::atomic_llong;
using VIGRA_THREADING_NAMESPACE::atomic_ullong;
// using VIGRA_THREADING_NAMESPACE::atomic_char16_t; // not in boost
// using VIGRA_THREADING_NAMESPACE::atomic_char32_t; // not in boost
using VIGRA_THREADING_NAMESPACE::atomic_wchar_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least8_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least8_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least16_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least16_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least32_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least32_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_least64_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_least64_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast8_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast8_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast16_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast16_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast32_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast32_t;
using VIGRA_THREADING_NAMESPACE::atomic_int_fast64_t;
using VIGRA_THREADING_NAMESPACE::atomic_uint_fast64_t;
using VIGRA_THREADING_NAMESPACE::atomic_intptr_t;
using VIGRA_THREADING_NAMESPACE::atomic_uintptr_t;
using VIGRA_THREADING_NAMESPACE::atomic_size_t;
using VIGRA_THREADING_NAMESPACE::atomic_ptrdiff_t;
using VIGRA_THREADING_NAMESPACE::atomic_intmax_t;
using VIGRA_THREADING_NAMESPACE::atomic_uintmax_t;

using VIGRA_THREADING_NAMESPACE::memory_order;
using VIGRA_THREADING_NAMESPACE::memory_order_relaxed;
using VIGRA_THREADING_NAMESPACE::memory_order_release;
using VIGRA_THREADING_NAMESPACE::memory_order_acquire;
using VIGRA_THREADING_NAMESPACE::memory_order_consume;
using VIGRA_THREADING_NAMESPACE::memory_order_acq_rel;
using VIGRA_THREADING_NAMESPACE::memory_order_seq_cst;

using VIGRA_THREADING_NAMESPACE::atomic_thread_fence;
using VIGRA_THREADING_NAMESPACE::atomic_signal_fence;

// using VIGRA_THREADING_NAMESPACE::atomic_is_lock_free;
// using VIGRA_THREADING_NAMESPACE::atomic_storeatomic_store_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_loadatomic_load_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_exchangeatomic_exchange_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_weak_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong;
// using VIGRA_THREADING_NAMESPACE::atomic_compare_exchange_strong_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_addatomic_fetch_add_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_subatomic_fetch_sub_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_andatomic_fetch_and_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_oratomic_fetch_or_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_fetch_xoratomic_fetch_xor_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_flag_test_and_setatomic_flag_test_and_set_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_flag_clearatomic_flag_clear_explicit;
// using VIGRA_THREADING_NAMESPACE::atomic_init;
// using VIGRA_THREADING_NAMESPACE::kill_dependency;

#else  // VIGRA_HAS_ATOMIC not defined

enum memory_order {
    memory_order_relaxed,
    memory_order_release,
    memory_order_acquire,
    memory_order_consume,
    memory_order_acq_rel,
    memory_order_seq_cst
};

#ifdef _MSC_VER

template <int SIZE=4>
struct atomic_long_impl
{
    typedef LONG value_type;

    static long load(value_type const & val)
    {
        long res = val;
        MemoryBarrier();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        MemoryBarrier();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return InterlockedExchangeAdd(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return InterlockedExchangeAdd(&dest, -val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = InterlockedCompareExchange(&dest, new_val, old_val);
        return check_val == old_val;
    }
};

template <>
struct atomic_long_impl<8>
{
    typedef LONGLONG value_type;

    static long load(value_type const & val)
    {
        long res = val;
        MemoryBarrier();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        MemoryBarrier();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return InterlockedExchangeAdd64(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return InterlockedExchangeAdd64(&dest, -val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = InterlockedCompareExchange64(&dest, new_val, old_val);
        return check_val == old_val;
    }
};

#else

template <int SIZE=4>
struct atomic_long_impl
{
    typedef long value_type;

    static long load(value_type const & val)
    {
        long res = val;
        __sync_synchronize();
        return res;
    }

    static void store(value_type & dest, long val)
    {
        __sync_synchronize();
        dest = val;
    }

    static long add(value_type & dest, long val)
    {
        return __sync_fetch_and_add(&dest, val);
    }

    static long sub(value_type & dest, long val)
    {
        return __sync_fetch_and_sub(&dest, val);
    }

    static bool compare_exchange(value_type & dest, long & old_val, long new_val)
    {
        long check_val = old_val;
        old_val = __sync_val_compare_and_swap(&dest, old_val, new_val);
        return check_val == old_val;
    }
};

#endif // _MSC_VER

struct atomic_long
{
    typedef atomic_long_impl<sizeof(long)>::value_type value_type;

    atomic_long(long v = 0)
    : value_(v)
    {}

    atomic_long & operator=(long val)
    {
        store(val);
        return *this;
    }

    long load(memory_order = memory_order_seq_cst) const
    {
        return atomic_long_impl<sizeof(long)>::load(value_);
    }

    void store(long v, memory_order = memory_order_seq_cst)
    {
        atomic_long_impl<sizeof(long)>::store(value_, v);
    }

    long fetch_add(long v, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::add(value_, v);
    }

    long fetch_sub(long v, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::sub(value_, v);
    }

    bool compare_exchange_strong(long & old_val, long new_val, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
    }

    bool compare_exchange_weak(long & old_val, long new_val, memory_order = memory_order_seq_cst)
    {
        return atomic_long_impl<sizeof(long)>::compare_exchange(value_, old_val, new_val);
    }

    value_type value_;
};

#endif // VIGRA_HAS_ATOMIC

}} // namespace vigra::threading

#undef VIGRA_THREADING_NAMESPACE

#endif // not VIGRA_SINGLE_THREADED

#endif // VIGRA_THREADING_HXX
<|endoftext|>