<commit_before>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2021-present David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Core/TicToc.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/ImageProcessing/LevelSets/FiniteDifferences.hpp>

#include "Utilities.hpp"

#include <iostream>
#include <numeric>
#include <set>

namespace sara = DO::Sara;

auto radial_distance(sara::Image<float>& phi, const Eigen::Vector2f& center)
{
  for (auto y = 0; y < phi.height(); ++y)
  {
    for (auto x = 0; x < phi.width(); ++x)
    {
      const auto xy = Eigen::Vector2f(x, y);
      phi(x, y) = (xy - center).norm();
    }
  }
}

enum State : std::uint8_t
{
  Alive = 0,
  Trial = 1,
  Far = 2,
  Forbidden = 3
};

struct CoordsValue
{
  Eigen::Vector2i coords;
  float val;

  inline auto operator<(const CoordsValue& other) const
  {
    return val < other.val;
  }
};

template <typename T>
auto solve_eikonal_equation_2d(const Eigen::Vector2i& x, const T fx,
                               const sara::Image<T>& u)
{
  const auto u0 = std::min(u(x - Eigen::Vector2i::Unit(0)),
                           u(x + Eigen::Vector2i::Unit(0)));
  const auto u1 = std::min(u(x - Eigen::Vector2i::Unit(1)),
                           u(x + Eigen::Vector2i::Unit(1)));

  const auto fx_inverse = 1 / (fx * fx);

  const auto a = 2.f;
  const auto b = -2 * (u0 + u1);
  const auto c = u0 * u0 + u1 * u1 - fx_inverse * fx_inverse;

  const auto delta = b * b - 4 * a * c;

  auto r0 = float{};
  if (delta >= 0)
    r0 = (-b + std::sqrt(delta)) / (2 * a);
  else
    r0 = std::min(u0, u1) + fx_inverse;

  return r0;
}

GRAPHICS_MAIN()
{
#define REAL_IMAGE
#ifdef REAL_IMAGE
  const auto image = sara::imread<float>(                       //
      "/Users/david/GitLab/DO-CV/sara/data/stinkbug.png"        //
  );

  constexpr auto sigma = 3.f;
  const auto image_blurred = sara::gaussian(image, sigma);
  const auto laplacian = sara::laplacian(image_blurred);

  const auto grad = sara::gradient(image_blurred);
  const auto grad_mag =
      grad.cwise_transform([](const auto& v) { return v.squaredNorm(); });

  static_assert(std::is_same_v<decltype(image_blurred), decltype(grad_mag)>);

  // Create the speed function from the gradient magnitude.
  auto speed_times_dt = grad_mag.cwise_transform(
      [](const auto& v) { return std::exp(-v); }  //
  );

  // Extract the zero level set.
  const auto zeros = sara::extract_zero_level_set(laplacian);

  sara::create_window(image.sizes());
  sara::display(sara::color_rescale(laplacian));
#else
  const auto w = 512;
  const auto h = 512;
  auto image = sara::Image<float, 2>{w, h};
  radial_distance(image, Eigen::Vector2f(w, h) / 2);

  const auto grad = sara::gradient(image);
  const auto grad_mag =
      grad.cwise_transform([](const auto& v) { return v.norm(); });

  auto speed_times_dt = sara::Image<float, 2>{w, h};
  speed_times_dt.flat_array().fill(1);

  const auto zeros = std::vector{Eigen::Vector2i(w/2, h/2)};

  sara::create_window(image.sizes());
  sara::display(sara::color_rescale(image));
#endif

  for (const auto& p : zeros)
    sara::draw_point(p.x(), p.y(), sara::Red8);

  auto to_index = [&image](const Eigen::Vector2i& p) {
    return p.y() * image.width() + p.x();
  };
  // auto to_coords = [&image](const std::int32_t i) -> Eigen::Vector2i {
  //   const auto y = i / image.width();
  //   const auto x = i - y * image.width();
  //   return {x, y};
  // };

  // Fast marching.
  sara::tic();
  auto states = sara::Image<State>{image.sizes()};
  auto distances = sara::Image<float>{image.sizes()};
  auto predecessors = sara::Image<std::int32_t>{image.sizes()};
  states.flat_array().fill(State::Far);
  distances.flat_array().fill(std::numeric_limits<float>::max());
  predecessors.flat_array().fill(-1);

  const auto deltas = std::array<Eigen::Vector2i, 8>{
      Eigen::Vector2i{-1, 0},  //
      Eigen::Vector2i{+1, 0},  //
      Eigen::Vector2i{0, -1},  //
      Eigen::Vector2i{0, +1},   //
      Eigen::Vector2i{-1, -1},  //
      Eigen::Vector2i{-1, +1},  //
      Eigen::Vector2i{+1, -1},  //
      Eigen::Vector2i{+1, +1}   //
  };

  // Initialize the alive set from the zero level set.
  for (const auto& p : zeros)
  {
    states(p) = State::Alive;
    distances(p) = 0;
  }

  // Initialize the trial set.
  auto trial_set = std::multiset<CoordsValue>{};
  for (const auto& p : zeros)
  {
    for (const auto& delta : deltas)
    {
      const Eigen::Vector2i n = p + delta;
      if (n.x() < 0 || n.x() >= image.width() ||  //
          n.y() < 0 || n.y() >= image.height())
        continue;

      if (states(n) == State::Alive || states(n) == State::Forbidden)
        continue;

      states(n) = State::Trial;
      distances(n) = speed_times_dt(n);
      predecessors(n) = to_index(p);

      trial_set.insert({n, distances(n)});
    }
  }

  auto increase_priority = [&trial_set, &distances](const Eigen::Vector2i& p,
                                                    float val) {
    if (val < distances(p))
    {
      const auto p_it = trial_set.find({p, distances(p)});
      trial_set.erase(p_it);
      trial_set.insert({p, val});
    }
  };

  // Propagate the wavefront.
  while (!trial_set.empty())
  {
    // Extract the closest trial point.
    const auto p = trial_set.begin()->coords;
    trial_set.erase(trial_set.begin());

    //  sara::draw_point(p.x(), p.y(), sara::Green8);

    // Update the neighbors.
    for (const auto& delta : deltas)
    {
      const Eigen::Vector2i n = p + delta;
      if (n.x() < 1 || n.x() >= image.width() -1 ||  //
          n.y() < 1 || n.y() >= image.height() -1)
        continue;

      if (states(n) == State::Alive || states(n) == State::Forbidden)
        continue;

      // At this point, a neighbor is either `Far` or `Trial` now.
      //
      // Update its distance value in both cases.
      const auto new_dist_n = solve_eikonal_equation_2d(n, speed_times_dt(n), distances);
      if (new_dist_n < distances(n))
      {
        distances(n) = new_dist_n;
        predecessors(n) = to_index(p);
      }

      if (states(n) == State::Far)
      {
        // Update its state.
        states(n) = State::Trial;

        // Insert it into the list of trial points.
        trial_set.insert({n, distances(n)});
      }

      // Increase the priority of the point if necessary.
      if (states(n) == State::Trial)
        increase_priority(n, distances(n));
    }
  }
  sara::toc("Fast Marching 2D");

  for (auto y = 0; y < distances.height(); ++y)
    for (auto x = 0; x < distances.width(); ++x)
      if (distances(x, y) == std::numeric_limits<float>::max())
        distances(x, y) = 0;

  auto d = distances.flat_array();
  const auto dmax = d.maxCoeff();
  d /= dmax;
  SARA_CHECK(dmax);
  sara::display(distances);
  sara::get_key();

  return 0;
}
<commit_msg>MAINT: fix potential crash.<commit_after>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2021-present David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Core/TicToc.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/ImageProcessing/LevelSets/FiniteDifferences.hpp>

#include "Utilities.hpp"

#include <iostream>
#include <numeric>
#include <set>

namespace sara = DO::Sara;

auto radial_distance(sara::Image<float>& phi, const Eigen::Vector2f& center)
{
  for (auto y = 0; y < phi.height(); ++y)
  {
    for (auto x = 0; x < phi.width(); ++x)
    {
      const auto xy = Eigen::Vector2f(x, y);
      phi(x, y) = (xy - center).norm();
    }
  }
}

enum State : std::uint8_t
{
  Alive = 0,
  Trial = 1,
  Far = 2,
  Forbidden = 3
};

struct CoordsValue
{
  Eigen::Vector2i coords;
  float val;

  inline auto operator<(const CoordsValue& other) const
  {
    return val < other.val;
  }
};

template <typename T>
auto solve_eikonal_equation_2d(const Eigen::Vector2i& x, const T fx,
                               const sara::Image<T>& u)
{
  const auto u0 = std::min(u(x - Eigen::Vector2i::Unit(0)),
                           u(x + Eigen::Vector2i::Unit(0)));
  const auto u1 = std::min(u(x - Eigen::Vector2i::Unit(1)),
                           u(x + Eigen::Vector2i::Unit(1)));

  const auto fx_inverse = 1 / (fx * fx);

  const auto a = 2.f;
  const auto b = -2 * (u0 + u1);
  const auto c = u0 * u0 + u1 * u1 - fx_inverse * fx_inverse;

  const auto delta = b * b - 4 * a * c;

  auto r0 = float{};
  if (delta >= 0)
    r0 = (-b + std::sqrt(delta)) / (2 * a);
  else
    r0 = std::min(u0, u1) + fx_inverse;

  return r0;
}

GRAPHICS_MAIN()
{
#define REAL_IMAGE
#ifdef REAL_IMAGE
  const auto image = sara::imread<float>(                       //
#ifdef __APPLE__
      "/Users/david/GitLab/DO-CV/sara/data/stinkbug.png"        //
#else
      "/home/david/GitLab/DO-CV/sara/data/stinkbug.png"        //
#endif
  );

  constexpr auto sigma = 3.f;
  const auto image_blurred = sara::gaussian(image, sigma);
  const auto laplacian = sara::laplacian(image_blurred);

  const auto grad = sara::gradient(image_blurred);
  const auto grad_mag =
      grad.cwise_transform([](const auto& v) { return v.squaredNorm(); });

  static_assert(std::is_same_v<decltype(image_blurred), decltype(grad_mag)>);

  // Create the speed function from the gradient magnitude.
  auto speed_times_dt = grad_mag.cwise_transform(
      [](const auto& v) { return std::exp(-v); }  //
  );

  // Extract the zero level set.
  const auto zeros = sara::extract_zero_level_set(laplacian);

  sara::create_window(image.sizes());
  sara::display(sara::color_rescale(laplacian));
#else
  const auto w = 512;
  const auto h = 512;
  auto image = sara::Image<float, 2>{w, h};
  radial_distance(image, Eigen::Vector2f(w, h) / 2);

  const auto grad = sara::gradient(image);
  const auto grad_mag =
      grad.cwise_transform([](const auto& v) { return v.norm(); });

  auto speed_times_dt = sara::Image<float, 2>{w, h};
  speed_times_dt.flat_array().fill(1);

  const auto zeros = std::vector{Eigen::Vector2i(w/2, h/2)};

  sara::create_window(image.sizes());
  sara::display(sara::color_rescale(image));
#endif

  for (const auto& p : zeros)
    sara::draw_point(p.x(), p.y(), sara::Red8);

  auto to_index = [&image](const Eigen::Vector2i& p) {
    return p.y() * image.width() + p.x();
  };
  // auto to_coords = [&image](const std::int32_t i) -> Eigen::Vector2i {
  //   const auto y = i / image.width();
  //   const auto x = i - y * image.width();
  //   return {x, y};
  // };

  // Fast marching.
  sara::tic();
  auto states = sara::Image<State>{image.sizes()};
  auto distances = sara::Image<float>{image.sizes()};
  auto predecessors = sara::Image<std::int32_t>{image.sizes()};
  states.flat_array().fill(State::Far);
  distances.flat_array().fill(std::numeric_limits<float>::max());
  predecessors.flat_array().fill(-1);

  const auto deltas = std::array<Eigen::Vector2i, 8>{
      Eigen::Vector2i{-1, 0},  //
      Eigen::Vector2i{+1, 0},  //
      Eigen::Vector2i{0, -1},  //
      Eigen::Vector2i{0, +1},   //
      Eigen::Vector2i{-1, -1},  //
      Eigen::Vector2i{-1, +1},  //
      Eigen::Vector2i{+1, -1},  //
      Eigen::Vector2i{+1, +1}   //
  };

  // Initialize the alive set from the zero level set.
  for (const auto& p : zeros)
  {
    states(p) = State::Alive;
    distances(p) = 0;
  }

  // Initialize the trial set.
  auto trial_set = std::multiset<CoordsValue>{};
  for (const auto& p : zeros)
  {
    for (const auto& delta : deltas)
    {
      const Eigen::Vector2i n = p + delta;
      if (n.x() < 0 || n.x() >= image.width() ||  //
          n.y() < 0 || n.y() >= image.height())
        continue;

      if (states(n) == State::Alive || states(n) == State::Forbidden)
        continue;

      states(n) = State::Trial;
      distances(n) = speed_times_dt(n);
      predecessors(n) = to_index(p);

      trial_set.insert({n, distances(n)});
    }
  }

  auto increase_priority = [&trial_set, &distances](const Eigen::Vector2i& p,
                                                    float val) {
    if (val < distances(p))
    {
      const auto p_it = trial_set.find({p, distances(p)});
      if (p_it != trial_set.end() && p_it->coords == p)
        trial_set.erase(p_it);
      trial_set.insert({p, val});
    }
  };

  // Propagate the wavefront.
  while (!trial_set.empty())
  {
    // Extract the closest trial point.
    const auto p = trial_set.begin()->coords;
    trial_set.erase(trial_set.begin());

    //  sara::draw_point(p.x(), p.y(), sara::Green8);
    if (states(p) == State::Alive)
    {
      std::cout << "OOPS!!!" << std::endl;
      continue;
    }

    // Update the neighbors.
    for (const auto& delta : deltas)
    {
      const Eigen::Vector2i n = p + delta;
      if (n.x() < 1 || n.x() >= image.width() -1 ||  //
          n.y() < 1 || n.y() >= image.height() -1)
        continue;

      if (states(n) == State::Alive || states(n) == State::Forbidden)
        continue;

      // At this point, a neighbor is either `Far` or `Trial` now.
      //
      // Update its distance value in both cases.
      const auto new_dist_n = solve_eikonal_equation_2d(n, speed_times_dt(n), distances);
      if (new_dist_n < distances(n))
      {
        distances(n) = new_dist_n;
        predecessors(n) = to_index(p);
      }

      if (states(n) == State::Far)
      {
        // Update its state.
        states(n) = State::Trial;

        // Insert it into the list of trial points.
        trial_set.insert({n, distances(n)});
      }

      // Increase the priority of the point if necessary.
      if (states(n) == State::Trial)
        increase_priority(n, distances(n));
    }
  }
  sara::toc("Fast Marching 2D");

  for (auto y = 0; y < distances.height(); ++y)
    for (auto x = 0; x < distances.width(); ++x)
      if (distances(x, y) == std::numeric_limits<float>::max())
        distances(x, y) = 0;

  auto d = distances.flat_array();
  const auto dmax = d.maxCoeff();
  d /= dmax;
  SARA_CHECK(dmax);
  sara::display(distances);
  sara::get_key();

  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2012 Andrew C. Morrow
//
// 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.

#ifndef included_108FBB04_F426_414D_9EDD_B4D2AF941E96
#define included_108FBB04_F426_414D_9EDD_B4D2AF941E96

#include <cassert>
#include <initializer_list>
#include <memory>
#include <system_error>
#include <type_traits>

namespace acm {

    namespace detail  {

        namespace adl_swap_ns {
            using std::swap;

            template <class T>
            struct is_nothrow_swappable_test {
                static bool constexpr value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
            };
        } // namespace adl_swap_ns

        // This really should be part of C++
        template <class T>
        struct is_nothrow_swappable
            : std::integral_constant<bool, adl_swap_ns::is_nothrow_swappable_test<T>::value>
        {};

    } // namespace detail

    template<typename E, typename T>
    class error_or {

    public:
        using error_type = E;
        using value_type = T;

        inline error_or() noexcept(std::is_nothrow_default_constructible<value_type>::value) {
            new(&val_.value) value_type;
        }

        inline error_or(error_type error) noexcept(std::is_nothrow_move_constructible<error_type>::value)
            : ok_(false) {
            assert(error);
            new(&val_.error) error_type(std::move(error));
        }

        inline error_or(value_type value) noexcept(std::is_nothrow_move_constructible<value_type>::value) {
            new(&val_.value) value_type(std::move(value));
        }

        template<typename U = value_type>
        inline error_or(std::initializer_list<typename U::value_type> values) noexcept(std::is_nothrow_constructible<U, std::initializer_list<typename U::value_type>>::value) {
            new(&val_.value) value_type(values);
        }

        // template<typename... Args>
        // inline error_or(Args&&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
        // {
        //     new(&val_.value) value_type(std::forward<Args>(args)...);
        // }

        inline error_or(const error_or& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                        std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        inline error_or(error_or&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                    std::is_nothrow_copy_constructible<error_type>::value) and
                                                   (std::is_nothrow_copy_constructible<value_type>::value or
                                                    std::is_nothrow_copy_constructible<value_type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(std::move_if_noexcept(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(const error_or<error_type, U>& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                                       std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(error_or<error_type, U>&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                                   std::is_nothrow_copy_constructible<error_type>::value) and
                                                                  (std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value or
                                                                   std::is_nothrow_constructible<value_type, typename std::add_lvalue_reference<U>::type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(move_if_noexcept_from(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        void swap(error_or& other) noexcept {
            other.sfinae_swap(*this);
        }

        friend inline void swap(error_or& a, error_or& b) noexcept {
            a.swap(b);
        }

        inline error_or& operator=(error_type error) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<error_type>::type>::value) {
            error_or(std::move(error)).swap(*this);
            return *this;
        }

        inline error_or& operator=(value_type value) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<value_type>::type>::value) {
            error_or(std::move(value)).swap(*this);
            return *this;
        }

        inline error_or& operator=(error_or other) noexcept(std::is_nothrow_move_constructible<error_or>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        template<typename U>
        inline error_or& operator=(error_or<error_type, U> other) noexcept(std::is_nothrow_constructible<error_or, error_or<E, U>&&>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        inline ~error_or() noexcept(std::is_nothrow_destructible<error_type>::value and
                                    std::is_nothrow_destructible<value_type>::value) {
            if (ok_)
                val_.value.~value_type();
            else
                val_.error.~error_type();
        }

        inline bool ok() const noexcept {
            return ok_;
        }

        inline explicit operator bool() const noexcept {
            return ok_;
        }

        inline const error_type& error() const noexcept {
            assert(!ok_);
            return val_.error;
        }

        inline value_type& value() noexcept {
            assert(ok_);
            return val_.value;
        }

        inline const value_type& value() const noexcept {
            assert(ok_);
            return val_.value;
        }

        inline error_type&& release_error() noexcept {
            assert(!ok_);
            return std::move(val_.error);
        }

        inline value_type&& release_value() noexcept {
            assert(ok_);
            return std::move(val_.value);
        }

    private:
        union val {
            // The lifecycle of members is handled by the enclosing class.
            inline val() noexcept {}
            inline ~val() noexcept {}
            value_type value;
            error_type error;
        } val_;

        bool ok_ = true;

        static constexpr bool is_nothrow_swappable =
            detail::is_nothrow_swappable<error_type>::value and
            detail::is_nothrow_swappable<value_type>::value and
            std::is_nothrow_move_constructible<error_type>::value and
            std::is_nothrow_move_constructible<value_type>::value and
            std::is_nothrow_destructible<error_type>::value and
            std::is_nothrow_destructible<value_type>::value;

        template<typename U = value_type>
        typename std::enable_if<error_or<error_type, U>::is_nothrow_swappable>::type sfinae_swap(error_or& other) noexcept {
            using std::swap;

            if (ok_ == other.ok_) {
                if (ok_)
                    swap(val_.value, other.val_.value);
                else
                    swap(val_.error, other.val_.error);
            } else {
                if (ok_) {
                    new(&val_.error) error_type(std::move(other.val_.error));
                    new(&other.val_.value) T(std::move(val_.value));
                    val_.value.~T();
                    other.val_.error.~error_type();
                } else {
                    new(&other.val_.error) error_type(std::move(val_.error));
                    new(&val_.value) T(std::move(other.val_.value));
                    other.val_.value.~T();
                    val_.error.~error_type();
                }
                swap(ok_, other.ok_);
            }
        }

        template<typename U>
        typename std::conditional
        <
            !std::is_nothrow_constructible<T, typename std::add_rvalue_reference<U>::type>::value and std::is_constructible<U, typename std::add_lvalue_reference<U>::type>::value,
            const T&,
            T&&
            >::type
        move_if_noexcept_from(U& u) {
            return std::move(u);
        }

    };

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator==(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs.value() == rhs.value()) and
                                                                                noexcept(lhs.error() == rhs.error())) {
        if (lhs.ok() == rhs.ok()) {
            if (lhs.ok()) {
                return lhs.value() == rhs.value();
            } else {
                return lhs.error() == rhs.error();
            }
        }
        return false;
    }

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator!=(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs == rhs)) {
        return not lhs == rhs;
    }

    template<typename T>
    using error_code_or = error_or<std::error_code, T>;

    template<typename T>
    using error_condition_or = error_or<std::error_condition, T>;

    template<typename T>
    using error_code_or_unique = error_code_or<std::unique_ptr<T>>;

    template<typename T>
    using error_condition_or_unique = error_condition_or<std::unique_ptr<T>>;

} // namespace acm

#endif // included_108FBB04_F426_414D_9EDD_B4D2AF941E96
<commit_msg>s/copy/move in move constructor noexcept specification<commit_after>// Copyright 2012 Andrew C. Morrow
//
// 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.

#ifndef included_108FBB04_F426_414D_9EDD_B4D2AF941E96
#define included_108FBB04_F426_414D_9EDD_B4D2AF941E96

#include <cassert>
#include <initializer_list>
#include <memory>
#include <system_error>
#include <type_traits>

namespace acm {

    namespace detail  {

        namespace adl_swap_ns {
            using std::swap;

            template <class T>
            struct is_nothrow_swappable_test {
                static bool constexpr value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
            };
        } // namespace adl_swap_ns

        // This really should be part of C++
        template <class T>
        struct is_nothrow_swappable
            : std::integral_constant<bool, adl_swap_ns::is_nothrow_swappable_test<T>::value>
        {};

    } // namespace detail

    template<typename E, typename T>
    class error_or {

    public:
        using error_type = E;
        using value_type = T;

        inline error_or() noexcept(std::is_nothrow_default_constructible<value_type>::value) {
            new(&val_.value) value_type;
        }

        inline error_or(error_type error) noexcept(std::is_nothrow_move_constructible<error_type>::value)
            : ok_(false) {
            assert(error);
            new(&val_.error) error_type(std::move(error));
        }

        inline error_or(value_type value) noexcept(std::is_nothrow_move_constructible<value_type>::value) {
            new(&val_.value) value_type(std::move(value));
        }

        template<typename U = value_type>
        inline error_or(std::initializer_list<typename U::value_type> values) noexcept(std::is_nothrow_constructible<U, std::initializer_list<typename U::value_type>>::value) {
            new(&val_.value) value_type(values);
        }

        // template<typename... Args>
        // inline error_or(Args&&... args) noexcept(std::is_nothrow_constructible<value_type, Args...>::value)
        // {
        //     new(&val_.value) value_type(std::forward<Args>(args)...);
        // }

        inline error_or(const error_or& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                        std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        inline error_or(error_or&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                    std::is_nothrow_copy_constructible<error_type>::value) and
                                                   (std::is_nothrow_move_constructible<value_type>::value or
                                                    std::is_nothrow_copy_constructible<value_type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(std::move_if_noexcept(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(const error_or<error_type, U>& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                                       std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(error_or<error_type, U>&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                                   std::is_nothrow_copy_constructible<error_type>::value) and
                                                                  (std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value or
                                                                   std::is_nothrow_constructible<value_type, typename std::add_lvalue_reference<U>::type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(move_if_noexcept_from(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        void swap(error_or& other) noexcept {
            other.sfinae_swap(*this);
        }

        friend inline void swap(error_or& a, error_or& b) noexcept {
            a.swap(b);
        }

        inline error_or& operator=(error_type error) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<error_type>::type>::value) {
            error_or(std::move(error)).swap(*this);
            return *this;
        }

        inline error_or& operator=(value_type value) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<value_type>::type>::value) {
            error_or(std::move(value)).swap(*this);
            return *this;
        }

        inline error_or& operator=(error_or other) noexcept(std::is_nothrow_move_constructible<error_or>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        template<typename U>
        inline error_or& operator=(error_or<error_type, U> other) noexcept(std::is_nothrow_constructible<error_or, error_or<E, U>&&>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        inline ~error_or() noexcept(std::is_nothrow_destructible<error_type>::value and
                                    std::is_nothrow_destructible<value_type>::value) {
            if (ok_)
                val_.value.~value_type();
            else
                val_.error.~error_type();
        }

        inline bool ok() const noexcept {
            return ok_;
        }

        inline explicit operator bool() const noexcept {
            return ok_;
        }

        inline const error_type& error() const noexcept {
            assert(!ok_);
            return val_.error;
        }

        inline value_type& value() noexcept {
            assert(ok_);
            return val_.value;
        }

        inline const value_type& value() const noexcept {
            assert(ok_);
            return val_.value;
        }

        inline error_type&& release_error() noexcept {
            assert(!ok_);
            return std::move(val_.error);
        }

        inline value_type&& release_value() noexcept {
            assert(ok_);
            return std::move(val_.value);
        }

    private:
        union val {
            // The lifecycle of members is handled by the enclosing class.
            inline val() noexcept {}
            inline ~val() noexcept {}
            value_type value;
            error_type error;
        } val_;

        bool ok_ = true;

        static constexpr bool is_nothrow_swappable =
            detail::is_nothrow_swappable<error_type>::value and
            detail::is_nothrow_swappable<value_type>::value and
            std::is_nothrow_move_constructible<error_type>::value and
            std::is_nothrow_move_constructible<value_type>::value and
            std::is_nothrow_destructible<error_type>::value and
            std::is_nothrow_destructible<value_type>::value;

        template<typename U = value_type>
        typename std::enable_if<error_or<error_type, U>::is_nothrow_swappable>::type sfinae_swap(error_or& other) noexcept {
            using std::swap;

            if (ok_ == other.ok_) {
                if (ok_)
                    swap(val_.value, other.val_.value);
                else
                    swap(val_.error, other.val_.error);
            } else {
                if (ok_) {
                    new(&val_.error) error_type(std::move(other.val_.error));
                    new(&other.val_.value) T(std::move(val_.value));
                    val_.value.~T();
                    other.val_.error.~error_type();
                } else {
                    new(&other.val_.error) error_type(std::move(val_.error));
                    new(&val_.value) T(std::move(other.val_.value));
                    other.val_.value.~T();
                    val_.error.~error_type();
                }
                swap(ok_, other.ok_);
            }
        }

        template<typename U>
        typename std::conditional
        <
            !std::is_nothrow_constructible<T, typename std::add_rvalue_reference<U>::type>::value and std::is_constructible<U, typename std::add_lvalue_reference<U>::type>::value,
            const T&,
            T&&
            >::type
        move_if_noexcept_from(U& u) {
            return std::move(u);
        }

    };

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator==(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs.value() == rhs.value()) and
                                                                                noexcept(lhs.error() == rhs.error())) {
        if (lhs.ok() == rhs.ok()) {
            if (lhs.ok()) {
                return lhs.value() == rhs.value();
            } else {
                return lhs.error() == rhs.error();
            }
        }
        return false;
    }

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator!=(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs == rhs)) {
        return not lhs == rhs;
    }

    template<typename T>
    using error_code_or = error_or<std::error_code, T>;

    template<typename T>
    using error_condition_or = error_or<std::error_condition, T>;

    template<typename T>
    using error_code_or_unique = error_code_or<std::unique_ptr<T>>;

    template<typename T>
    using error_condition_or_unique = error_condition_or<std::unique_ptr<T>>;

} // namespace acm

#endif // included_108FBB04_F426_414D_9EDD_B4D2AF941E96
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \brief Sample image acquisition urbi client.

#include <libport/cstdio>

#include <libport/cli.hh>
#include <libport/debug.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/option-parser.hh>
#include <libport/sysexits.hh>

#include <liburbi/compatibility.hh>
#include <urbi/package-info.hh>
#include <urbi/uconversion.hh>
#include <urbi/usyncclient.hh>

#include "monitor.hh"

using libport::program_name;

size_t imcount;
Monitor* mon = 0;
float scale;
urbi::UImage im;

/* Our callback function */
namespace
{
  static
  urbi::UCallbackAction
  showImage(const urbi::UMessage &msg)
  {
    if (msg.type != urbi::MESSAGE_DATA
        || msg.value->type != urbi::DATA_BINARY
        || msg.value->binary->type != urbi::BINARY_IMAGE)
      return urbi::URBI_CONTINUE;

    urbi::UImage& img = msg.value->binary->image;
    im.width = static_cast<int>(static_cast<float>(img.width) * scale);
    im.height = static_cast<int>(static_cast<float>(img.height) * scale);
    convert(img, im);

    /* Calculate framerate. */
    if (!(imcount % 20))
    {
      static int tme = 0;
      if (tme)
      {
        float it = msg.client.getCurrentTime() - tme;
        it = 20000.0 / it;
        printf("***Framerate: %f fps***\n", it);
      }
      tme = msg.client.getCurrentTime();
    }

    if (!mon)
      mon = new Monitor(im.width, im.height, "image");

    size_t sz = 3*im.width*im.height;
    mon->setImage((bits8 *) im.data, sz);
    ++imcount;
    return urbi::URBI_CONTINUE;
  }

  static
  void
  usage(libport::OptionParser& parser)
  {
    std::cout <<
      "usage: " << program_name() << " [options]\n"
      "Display images from an urbi server, or save one image if -o is given\n";
    parser.options_doc(std::cout);
    std::cout << std::endl <<
      "transfer Format : jpeg=transfer jpeg, raw=transfer raw\n"
      "save     Format : rgb , ycrcb, jpeg, ppm"
                << std::endl;
    ::exit(EX_OK);
  }

  static
  void
  version()
  {
    std::cout << "urbi-image" << std::endl
              << urbi::package_info() << std::endl
              << libport::exit(EX_OK);
  }

  /// Decode the image format string \s s.
  static
  int
  format(const std::string& s)
  {
    switch (s[0])
    {
    case 'r': return urbi::IMAGE_RGB;
    case 'y': return urbi::IMAGE_YCbCr;
    case 'p': return urbi::IMAGE_PPM;
    case 'j': return urbi::IMAGE_JPEG;
    default:
      std::cerr << program_name() << ": invalid format: "
                << s << std::endl
                << libport::exit(EX_USAGE);
    }
  }
}

GD_INIT();

int
main (int argc, char *argv[])
{
  libport::program_initialize(argc, argv);
  mon = 0;
  im.width = im.height = 0;
  im.size = 0;
  im.data = 0;
  im.imageFormat = urbi::IMAGE_RGB;

  libport::OptionValue
    arg_period("query images at given period (in milliseconds)",
               "period", 'p', "PERIOD"),
    arg_jpeg("jpeg compression factor (from 0 to 100, def 70)",
             "jpeg", 'j', "FACTOR"),
    arg_dev("query image on DEVICE.val (default: camera)",
            "device", 'd', "DEVICE"),
    arg_out("query and save one image to FILE",
            "output", 'o', "FILE"),
    arg_scale("rescale image with given FACTOR (display only)",
              "scale", 's', "FACTOR"),
    arg_form("select format of the image (rgb, ycrcb, jpeg, ppm)",
             "format", 'F', "FORMAT"),
    arg_resolution("select resolution of the image (0=biggest)",
                   "resolution", 'R', "RESOLUTION");
  libport::OptionFlag
    arg_rec("use reconstruct mode (for aibo)",
            "reconstruct", 'r');

  libport::OptionParser opt_parser;
  opt_parser << "Options:"
	     << libport::opts::help
	     << libport::opts::version
	     << libport::opts::host
	     << libport::opts::port
	     << libport::opts::port_file
	     << arg_period
	     << arg_form
	     << arg_rec
	     << arg_jpeg
	     << arg_dev
	     << arg_out
	     << arg_resolution
	     << arg_scale;

  opt_parser(libport::program_arguments());

  if (libport::opts::help.get())
    usage(opt_parser);
  if (libport::opts::version.get())
    version();

  std::string device = arg_dev.value("camera");

  std::string arg_format = arg_form.value("jpeg");
  scale = arg_scale.get<float>(1.0);

  /// Server port.
  int port = libport::opts::port.get<int>(urbi::UClient::URBI_PORT);
  if (libport::opts::port_file.filled())
    port = libport::file_contents_get<int>(libport::opts::port_file.value());
  urbi::USyncClient
    client(libport::opts::host.value(urbi::UClient::default_host()),
           port);

  if (client.error())
    std::cerr << libport::program_name() << ": client failed to set up"
	      << std::endl
              << libport::exit(1);

  if (1 < client.kernelMajor())
    client.send(SYNCLINE_WRAP("var uimg = Channel.new(\"uimg\")|;"));
  client.setCallback(showImage, "uimg");

  client.send(SYNCLINE_WRAP(
                "%s.resolution = %s|;\n"
                "%s.jpegfactor = %d|;\n"
                "%s.reconstruct = %d|;",
                device, arg_resolution.value("0"),
                device, arg_jpeg.get<int>(70),
                device, arg_rec.get() ? 1 : 0));

  if (arg_out.filled())
  {
    const char *file = arg_out.value().c_str();
    FILE *f = fopen(file, "w");
    if (!f)
      std::cerr << program_name() << ": cannot create file " << file
                << ": " << strerror(errno)
                << libport::exit(EX_OSERR);

    int fmt = format(arg_format);
    /* Use syncGetImage to save one image to a file. */
    char buff[1000000];
    size_t sz = sizeof buff;
    size_t w, h;
    client.syncGetImage(device.c_str(), buff, sz,
			fmt,
			(fmt == urbi::IMAGE_JPEG
			 ? urbi::URBI_TRANSMIT_JPEG
			 : urbi::URBI_TRANSMIT_YCbCr),
			w, h);
    size_t written = fwrite(buff, 1, sz, f);
    LIBPORT_USE(written);
    assert_eq(sz, written);
    fclose(f);
  }
  else
  {
    imcount = 0;
    int fmt = (arg_format[0] == 'r') ? 0 : 1;
    client.send(SYNCLINE_WRAP("%s.format = %d|;", device, fmt));
    client.waitForKernelVersion(true);
    std::string command;
    if (int period = arg_period.get<int>(0))
      command = SYNCLINE_WRAP("every (%dms) uimg << %s.val,",
                              period, device);
    else if (client.kernelMajor() < 2)
      command = SYNCLINE_WRAP("loop { uimg << %s.val; noop },", device);
    else
      command = SYNCLINE_WRAP
        ("%s.&val.notifyChange(closure() {\n"
         "  connectionTag:\n"
         "    this.send(%s.val.asString, \"uimg\")\n"
         "});",
         device, device);
    client.send(command);
    urbi::execute();
  }

  return 0;
}
<commit_msg>urbi-image: Debug messages.<commit_after>/*
 * Copyright (C) 2005-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \brief Sample image acquisition urbi client.

#include <libport/cstdio>

#include <libport/cli.hh>
#include <libport/debug.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/option-parser.hh>
#include <libport/sysexits.hh>

#include <liburbi/compatibility.hh>
#include <urbi/package-info.hh>
#include <urbi/uconversion.hh>
#include <urbi/usyncclient.hh>

#include "monitor.hh"

GD_CATEGORY(UrbiImage);

using libport::program_name;

size_t imcount;
Monitor* mon = 0;
float scale;
urbi::UImage im;

/* Our callback function */
namespace
{
  static
  urbi::UCallbackAction
  showImage(const urbi::UMessage &msg)
  {
    bool ko = msg.type != urbi::MESSAGE_DATA
        || msg.value->type != urbi::DATA_BINARY
        || msg.value->binary->type != urbi::BINARY_IMAGE;
    GD_FINFO_DUMP("Message on img channel, type %s, ok %s", msg.type, !ko);
    if (msg.value)
      GD_FINFO_DUMP("vtype %s btype %s", msg.value->type,
                    msg.value->binary->type);
    if (ko)
      return urbi::URBI_CONTINUE;

    urbi::UImage& img = msg.value->binary->image;
    im.width = static_cast<int>(static_cast<float>(img.width) * scale);
    im.height = static_cast<int>(static_cast<float>(img.height) * scale);
    convert(img, im);

    /* Calculate framerate. */
    if (!(imcount % 20))
    {
      static int tme = 0;
      if (tme)
      {
        float it = msg.client.getCurrentTime() - tme;
        it = 20000.0 / it;
        printf("***Framerate: %f fps***\n", it);
      }
      tme = msg.client.getCurrentTime();
    }

    if (!mon)
      mon = new Monitor(im.width, im.height, "image");

    size_t sz = 3*im.width*im.height;
    mon->setImage((bits8 *) im.data, sz);
    ++imcount;
    return urbi::URBI_CONTINUE;
  }

  static
  void
  usage(libport::OptionParser& parser)
  {
    std::cout <<
      "usage: " << program_name() << " [options]\n"
      "Display images from an urbi server, or save one image if -o is given\n";
    parser.options_doc(std::cout);
    std::cout << std::endl <<
      "transfer Format : jpeg=transfer jpeg, raw=transfer raw\n"
      "save     Format : rgb , ycrcb, jpeg, ppm"
                << std::endl;
    ::exit(EX_OK);
  }

  static
  void
  version()
  {
    std::cout << "urbi-image" << std::endl
              << urbi::package_info() << std::endl
              << libport::exit(EX_OK);
  }

  /// Decode the image format string \s s.
  static
  int
  format(const std::string& s)
  {
    switch (s[0])
    {
    case 'r': return urbi::IMAGE_RGB;
    case 'y': return urbi::IMAGE_YCbCr;
    case 'p': return urbi::IMAGE_PPM;
    case 'j': return urbi::IMAGE_JPEG;
    default:
      std::cerr << program_name() << ": invalid format: "
                << s << std::endl
                << libport::exit(EX_USAGE);
    }
  }
}

GD_INIT();

int
main (int argc, char *argv[])
{
  libport::program_initialize(argc, argv);
  mon = 0;
  im.width = im.height = 0;
  im.size = 0;
  im.data = 0;
  im.imageFormat = urbi::IMAGE_RGB;

  libport::OptionValue
    arg_period("query images at given period (in milliseconds)",
               "period", 'p', "PERIOD"),
    arg_jpeg("jpeg compression factor (from 0 to 100, def 70)",
             "jpeg", 'j', "FACTOR"),
    arg_dev("query image on DEVICE.val (default: camera)",
            "device", 'd', "DEVICE"),
    arg_out("query and save one image to FILE",
            "output", 'o', "FILE"),
    arg_scale("rescale image with given FACTOR (display only)",
              "scale", 's', "FACTOR"),
    arg_form("select format of the image (rgb, ycrcb, jpeg, ppm)",
             "format", 'F', "FORMAT"),
    arg_resolution("select resolution of the image (0=biggest)",
                   "resolution", 'R', "RESOLUTION");
  libport::OptionFlag
    arg_rec("use reconstruct mode (for aibo)",
            "reconstruct", 'r');

  libport::OptionParser opt_parser;
  opt_parser << "Options:"
	     << libport::opts::help
	     << libport::opts::version
	     << libport::opts::host
	     << libport::opts::port
	     << libport::opts::port_file
	     << arg_period
	     << arg_form
	     << arg_rec
	     << arg_jpeg
	     << arg_dev
	     << arg_out
	     << arg_resolution
	     << arg_scale;

  opt_parser(libport::program_arguments());

  if (libport::opts::help.get())
    usage(opt_parser);
  if (libport::opts::version.get())
    version();

  std::string device = arg_dev.value("camera");

  std::string arg_format = arg_form.value("jpeg");
  scale = arg_scale.get<float>(1.0);

  /// Server port.
  int port = libport::opts::port.get<int>(urbi::UClient::URBI_PORT);
  if (libport::opts::port_file.filled())
    port = libport::file_contents_get<int>(libport::opts::port_file.value());
  urbi::USyncClient
    client(libport::opts::host.value(urbi::UClient::default_host()),
           port);

  if (client.error())
    std::cerr << libport::program_name() << ": client failed to set up"
	      << std::endl
              << libport::exit(1);

  if (1 < client.kernelMajor())
    client.send(SYNCLINE_WRAP("var uimg = Channel.new(\"uimg\")|;"));
  client.setCallback(showImage, "uimg");

  client.send(SYNCLINE_WRAP(
                "%s.resolution = %s|;\n"
                "%s.jpegfactor = %d|;\n"
                "%s.reconstruct = %d|;",
                device, arg_resolution.value("0"),
                device, arg_jpeg.get<int>(70),
                device, arg_rec.get() ? 1 : 0));

  if (arg_out.filled())
  {
    const char *file = arg_out.value().c_str();
    FILE *f = fopen(file, "w");
    if (!f)
      std::cerr << program_name() << ": cannot create file " << file
                << ": " << strerror(errno)
                << libport::exit(EX_OSERR);

    int fmt = format(arg_format);
    /* Use syncGetImage to save one image to a file. */
    char buff[1000000];
    size_t sz = sizeof buff;
    size_t w, h;
    client.syncGetImage(device.c_str(), buff, sz,
			fmt,
			(fmt == urbi::IMAGE_JPEG
			 ? urbi::URBI_TRANSMIT_JPEG
			 : urbi::URBI_TRANSMIT_YCbCr),
			w, h);
    size_t written = fwrite(buff, 1, sz, f);
    LIBPORT_USE(written);
    assert_eq(sz, written);
    fclose(f);
  }
  else
  {
    imcount = 0;
    int fmt = (arg_format[0] == 'r') ? 0 : 1;
    client.send(SYNCLINE_WRAP("%s.format = %d|;", device, fmt));
    client.waitForKernelVersion(true);
    std::string command;
    if (int period = arg_period.get<int>(0))
      command = SYNCLINE_WRAP("every (%dms) uimg << %s.val,",
                              period, device);
    else if (client.kernelMajor() < 2)
      command = SYNCLINE_WRAP("loop { uimg << %s.val; noop },", device);
    else
      command = SYNCLINE_WRAP
        ("%s.&val.notifyChange(closure() {\n"
         "  connectionTag:\n"
         "    this.send(%s.val.asString, \"uimg\")\n"
         "});",
         device, device);
    client.send(command);
    urbi::execute();
  }

  return 0;
}
<|endoftext|>


<commit_before>// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines BugReporter, a utility class for generating
//  PathDiagnostics for analyses based on GRSimpleVals.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CFG.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/PathDiagnostic.h"
#include <sstream>

using namespace clang;

BugReporter::~BugReporter() {}
BugType::~BugType() {}
BugReport::~BugReport() {}
RangedBugReport::~RangedBugReport() {}

ExplodedGraph<ValueState>& BugReporter::getGraph() { return Eng.getGraph(); }

static inline Stmt* GetStmt(const ProgramPoint& P) {
  if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
    return PS->getStmt();
  }
  else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
    return BE->getSrc()->getTerminator();
  }
  else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
    return BE->getFirstStmt();
  }

  assert (false && "Unsupported ProgramPoint.");
  return NULL;
}

static inline Stmt* GetStmt(const CFGBlock* B) {
  assert (!B->empty());
  return (*B)[0];
}

Stmt* BugReport::getStmt() const {
  return N ? GetStmt(N->getLocation()) : NULL;
}

static inline ExplodedNode<ValueState>*
GetNextNode(ExplodedNode<ValueState>* N) {
  return N->pred_empty() ? NULL : *(N->pred_begin());
}

static Stmt* GetLastStmt(ExplodedNode<ValueState>* N) {
  assert (isa<BlockEntrance>(N->getLocation()));

  for (N = GetNextNode(N); N; N = GetNextNode(N)) {

    ProgramPoint P = N->getLocation();

    if (PostStmt* PS = dyn_cast<PostStmt>(&P))
      return PS->getStmt();
  }

  return NULL;
}

PathDiagnosticPiece*
BugReport::getEndPath(BugReporter& BR,
                      ExplodedNode<ValueState>* EndPathNode) const {

  ProgramPoint ProgP = EndPathNode->getLocation();
  Stmt *S = NULL;

  if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP))
    if (BE->getBlock() == &BR.getCFG().getExit())
      S = GetLastStmt(EndPathNode);
  if (!S)
    S = GetStmt(ProgP);

  if (!S)
    return NULL;

  FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());

  PathDiagnosticPiece* P =
    new PathDiagnosticPiece(L, getDescription());

  const SourceRange *Beg, *End;
  getRanges(Beg, End);

  if (Beg == End) {
    if (Expr* E = dyn_cast<Expr>(S))
      P->addRange(E->getSourceRange());
  }
  else {
    assert (Beg < End);
    for (; Beg != End; ++Beg)
      P->addRange(*Beg);
  }

  return P;
}

void BugReport::getRanges(const SourceRange*& beg,
                          const SourceRange*& end) const {
  beg = NULL;
  end = NULL;
}

FullSourceLoc BugReport::getLocation(SourceManager& Mgr) {

  if (!N)
    return FullSourceLoc();

  Stmt* S = GetStmt(N->getLocation());

  if (!S)
    return FullSourceLoc();

  return FullSourceLoc(S->getLocStart(), Mgr);
}

PathDiagnosticPiece* BugReport::VisitNode(ExplodedNode<ValueState>* N,
                                          ExplodedNode<ValueState>* PrevN,
                                          ExplodedGraph<ValueState>& G,
                                          BugReporter& BR) {
  return NULL;
}

void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
                                         BugReport& R) {

  ExplodedNode<ValueState>* N = R.getEndNode();

  if (!N)
    return;

  llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(getGraph().Trim(&N, &N+1));

  // Find the sink in the trimmed graph.
  // FIXME: Should we eventually have a sink iterator?

  ExplodedNode<ValueState>* NewN = 0;

  for (ExplodedGraph<ValueState>::node_iterator
       I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {

    if (I->isSink()) {
      NewN = &*I;
      break;
    }
  }

  assert (NewN);
  assert (NewN->getLocation() == N->getLocation());

  N = NewN;

  if (PathDiagnosticPiece* Piece = R.getEndPath(*this, N))
    PD.push_back(Piece);
  else
    return;

  ExplodedNode<ValueState>* NextNode = N->pred_empty()
                                       ? NULL : *(N->pred_begin());

  SourceManager& SMgr = Ctx.getSourceManager();

  while (NextNode) {

    ExplodedNode<ValueState>* LastNode = N;
    N = NextNode;
    NextNode = GetNextNode(N);

    ProgramPoint P = N->getLocation();

    if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {

      CFGBlock* Src = BE->getSrc();
      CFGBlock* Dst = BE->getDst();

      Stmt* T = Src->getTerminator();

      if (!T)
        continue;

      FullSourceLoc L(T->getLocStart(), SMgr);

      switch (T->getStmtClass()) {
        default:
          break;

        case Stmt::GotoStmtClass:
        case Stmt::IndirectGotoStmtClass: {

          Stmt* S = GetStmt(LastNode->getLocation());

          if (!S)
            continue;

          std::ostringstream os;

          os << "Control jumps to line "
             << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

          PD.push_front(new PathDiagnosticPiece(L, os.str()));
          break;
        }

        case Stmt::SwitchStmtClass: {

          // Figure out what case arm we took.

          Stmt* S = Dst->getLabel();

          if (!S)
            continue;

          std::ostringstream os;

          switch (S->getStmtClass()) {
            default:
              continue;

            case Stmt::DefaultStmtClass: {

              os << "Control jumps to the 'default' case at line "
                 << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

              break;
            }

            case Stmt::CaseStmtClass: {

              os << "Control jumps to 'case ";

              Expr* CondE = cast<SwitchStmt>(T)->getCond();
              unsigned bits = Ctx.getTypeSize(CondE->getType());

              llvm::APSInt V1(bits, false);

              CaseStmt* Case = cast<CaseStmt>(S);

              if (!Case->getLHS()->isIntegerConstantExpr(V1, Ctx, 0, true)) {
                assert (false &&
                        "Case condition must evaluate to an integer constant.");
                continue;
              }

              os << V1.toString();

              // Get the RHS of the case, if it exists.

              if (Expr* E = Case->getRHS()) {

                llvm::APSInt V2(bits, false);

                if (!E->isIntegerConstantExpr(V2, Ctx, 0, true)) {
                  assert (false &&
                  "Case condition (RHS) must evaluate to an integer constant.");
                  continue;
                }

                os << " .. " << V2.toString();
              }

              os << ":'  at line "
                << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

              break;

            }
          }

          PD.push_front(new PathDiagnosticPiece(L, os.str()));
          break;
        }

        case Stmt::ConditionalOperatorClass: {

          std::ostringstream os;
          os << "'?' condition evaluates to ";

          if (*(Src->succ_begin()+1) == Dst)
            os << "false.";
          else
            os << "true.";

          PD.push_front(new PathDiagnosticPiece(L, os.str()));

          break;
        }

        case Stmt::DoStmtClass:  {

          if (*(Src->succ_begin()) == Dst) {

            std::ostringstream os;

            os << "Loop condition is true. Execution continues on line "
               << SMgr.getLogicalLineNumber(GetStmt(Dst)->getLocStart()) << '.';

            PD.push_front(new PathDiagnosticPiece(L, os.str()));
          }
          else
            PD.push_front(new PathDiagnosticPiece(L,
                              "Loop condition is false.  Exiting loop."));

          break;
        }

        case Stmt::WhileStmtClass:
        case Stmt::ForStmtClass: {

          if (*(Src->succ_begin()+1) == Dst) {

            std::ostringstream os;

            os << "Loop condition is false. Execution continues on line "
               << SMgr.getLogicalLineNumber(GetStmt(Dst)->getLocStart()) << '.';

            PD.push_front(new PathDiagnosticPiece(L, os.str()));
          }
          else
            PD.push_front(new PathDiagnosticPiece(L,
                            "Loop condition is true.  Entering loop body."));

          break;
        }

        case Stmt::IfStmtClass: {

          if (*(Src->succ_begin()+1) == Dst)
            PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
          else
            PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));

          break;
        }
      }
    }
    else
      if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode, *GTrim, *this))
        PD.push_front(piece);
  }
}

bool BugTypeCacheLocation::isCached(BugReport& R) {

  ExplodedNode<ValueState>* N = R.getEndNode();

  if (!N)
    return false;

  // Cache the location of the error.  Don't emit the same
  // warning for the same error type that occurs at the same program
  // location but along a different path.

  void* p = N->getLocation().getRawData();

  if (CachedErrors.count(p))
    return true;

  CachedErrors.insert(p);
  return false;
}

void BugReporter::EmitWarning(BugReport& R) {

  if (R.getBugType().isCached(R))
    return;

  llvm::OwningPtr<PathDiagnostic> D(new PathDiagnostic(R.getName()));
  GeneratePathDiagnostic(*D.get(), R);

  // Emit a full diagnostic for the path if we have a PathDiagnosticClient.

  if (PD && !D->empty()) {
    PD->HandlePathDiagnostic(D.take());
    return;
  }

  // We don't have a PathDiagnosticClient, but we can still emit a single
  // line diagnostic.  Determine the location.

  FullSourceLoc L = D->empty() ? R.getLocation(Ctx.getSourceManager())
                               : D->back()->getLocation();

  // Determine the range.

  const SourceRange *Beg, *End;

  if (!D->empty()) {
    Beg = D->back()->ranges_begin();
    End = D->back()->ranges_end();
  }
  else
    R.getRanges(Beg, End);

  if (PD) {
    PathDiagnosticPiece* piece = new PathDiagnosticPiece(L, R.getDescription());

    for ( ; Beg != End; ++Beg)
      piece->addRange(*Beg);

    D->push_back(piece);
    PD->HandlePathDiagnostic(D.take());
  }
  else {
    std::ostringstream os;
    os << "[CHECKER] ";

    if (D->empty())
      os << R.getDescription();
    else
      os << D->back()->getString();

    unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
                                              os.str().c_str());

    Diag.Report(L, ErrorDiag, NULL, 0, Beg, End - Beg);
  }
}
<commit_msg>For default branches in switch statements with no default label, print out the line we are going to.<commit_after>// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines BugReporter, a utility class for generating
//  PathDiagnostics for analyses based on GRSimpleVals.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CFG.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/PathDiagnostic.h"
#include <sstream>

using namespace clang;

BugReporter::~BugReporter() {}
BugType::~BugType() {}
BugReport::~BugReport() {}
RangedBugReport::~RangedBugReport() {}

ExplodedGraph<ValueState>& BugReporter::getGraph() { return Eng.getGraph(); }

static inline Stmt* GetStmt(const ProgramPoint& P) {
  if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
    return PS->getStmt();
  }
  else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
    return BE->getSrc()->getTerminator();
  }
  else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
    return BE->getFirstStmt();
  }

  assert (false && "Unsupported ProgramPoint.");
  return NULL;
}

static inline Stmt* GetStmt(const CFGBlock* B) {
  assert (!B->empty());
  return (*B)[0];
}

Stmt* BugReport::getStmt() const {
  return N ? GetStmt(N->getLocation()) : NULL;
}

static inline ExplodedNode<ValueState>*
GetNextNode(ExplodedNode<ValueState>* N) {
  return N->pred_empty() ? NULL : *(N->pred_begin());
}

static Stmt* GetLastStmt(ExplodedNode<ValueState>* N) {
  assert (isa<BlockEntrance>(N->getLocation()));

  for (N = GetNextNode(N); N; N = GetNextNode(N)) {

    ProgramPoint P = N->getLocation();

    if (PostStmt* PS = dyn_cast<PostStmt>(&P))
      return PS->getStmt();
  }

  return NULL;
}

PathDiagnosticPiece*
BugReport::getEndPath(BugReporter& BR,
                      ExplodedNode<ValueState>* EndPathNode) const {

  ProgramPoint ProgP = EndPathNode->getLocation();
  Stmt *S = NULL;

  if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP))
    if (BE->getBlock() == &BR.getCFG().getExit())
      S = GetLastStmt(EndPathNode);
  if (!S)
    S = GetStmt(ProgP);

  if (!S)
    return NULL;

  FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());

  PathDiagnosticPiece* P =
    new PathDiagnosticPiece(L, getDescription());

  const SourceRange *Beg, *End;
  getRanges(Beg, End);

  if (Beg == End) {
    if (Expr* E = dyn_cast<Expr>(S))
      P->addRange(E->getSourceRange());
  }
  else {
    assert (Beg < End);
    for (; Beg != End; ++Beg)
      P->addRange(*Beg);
  }

  return P;
}

void BugReport::getRanges(const SourceRange*& beg,
                          const SourceRange*& end) const {
  beg = NULL;
  end = NULL;
}

FullSourceLoc BugReport::getLocation(SourceManager& Mgr) {

  if (!N)
    return FullSourceLoc();

  Stmt* S = GetStmt(N->getLocation());

  if (!S)
    return FullSourceLoc();

  return FullSourceLoc(S->getLocStart(), Mgr);
}

PathDiagnosticPiece* BugReport::VisitNode(ExplodedNode<ValueState>* N,
                                          ExplodedNode<ValueState>* PrevN,
                                          ExplodedGraph<ValueState>& G,
                                          BugReporter& BR) {
  return NULL;
}

void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
                                         BugReport& R) {

  ExplodedNode<ValueState>* N = R.getEndNode();

  if (!N)
    return;

  llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(getGraph().Trim(&N, &N+1));

  // Find the sink in the trimmed graph.
  // FIXME: Should we eventually have a sink iterator?

  ExplodedNode<ValueState>* NewN = 0;

  for (ExplodedGraph<ValueState>::node_iterator
       I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {

    if (I->isSink()) {
      NewN = &*I;
      break;
    }
  }

  assert (NewN);
  assert (NewN->getLocation() == N->getLocation());

  N = NewN;

  if (PathDiagnosticPiece* Piece = R.getEndPath(*this, N))
    PD.push_back(Piece);
  else
    return;

  ExplodedNode<ValueState>* NextNode = N->pred_empty()
                                       ? NULL : *(N->pred_begin());

  SourceManager& SMgr = Ctx.getSourceManager();

  while (NextNode) {

    ExplodedNode<ValueState>* LastNode = N;
    N = NextNode;
    NextNode = GetNextNode(N);

    ProgramPoint P = N->getLocation();

    if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {

      CFGBlock* Src = BE->getSrc();
      CFGBlock* Dst = BE->getDst();

      Stmt* T = Src->getTerminator();

      if (!T)
        continue;

      FullSourceLoc L(T->getLocStart(), SMgr);

      switch (T->getStmtClass()) {
        default:
          break;

        case Stmt::GotoStmtClass:
        case Stmt::IndirectGotoStmtClass: {

          Stmt* S = GetStmt(LastNode->getLocation());

          if (!S)
            continue;

          std::ostringstream os;

          os << "Control jumps to line "
             << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

          PD.push_front(new PathDiagnosticPiece(L, os.str()));
          break;
        }

        case Stmt::SwitchStmtClass: {

          // Figure out what case arm we took.

          Stmt* S = Dst->getLabel();

          if (!S)
            continue;

          std::ostringstream os;

          switch (S->getStmtClass()) {
            default:
            case Stmt::DefaultStmtClass: {

              os << "Control jumps to the 'default' case at line "
                 << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

              break;
            }

            case Stmt::CaseStmtClass: {

              os << "Control jumps to 'case ";

              Expr* CondE = cast<SwitchStmt>(T)->getCond();
              unsigned bits = Ctx.getTypeSize(CondE->getType());

              llvm::APSInt V1(bits, false);

              CaseStmt* Case = cast<CaseStmt>(S);

              if (!Case->getLHS()->isIntegerConstantExpr(V1, Ctx, 0, true)) {
                assert (false &&
                        "Case condition must evaluate to an integer constant.");
                continue;
              }

              os << V1.toString();

              // Get the RHS of the case, if it exists.

              if (Expr* E = Case->getRHS()) {

                llvm::APSInt V2(bits, false);

                if (!E->isIntegerConstantExpr(V2, Ctx, 0, true)) {
                  assert (false &&
                  "Case condition (RHS) must evaluate to an integer constant.");
                  continue;
                }

                os << " .. " << V2.toString();
              }

              os << ":'  at line "
                << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";

              break;

            }
          }

          PD.push_front(new PathDiagnosticPiece(L, os.str()));
          break;
        }

        case Stmt::ConditionalOperatorClass: {

          std::ostringstream os;
          os << "'?' condition evaluates to ";

          if (*(Src->succ_begin()+1) == Dst)
            os << "false.";
          else
            os << "true.";

          PD.push_front(new PathDiagnosticPiece(L, os.str()));

          break;
        }

        case Stmt::DoStmtClass:  {

          if (*(Src->succ_begin()) == Dst) {

            std::ostringstream os;

            os << "Loop condition is true. Execution continues on line "
               << SMgr.getLogicalLineNumber(GetStmt(Dst)->getLocStart()) << '.';

            PD.push_front(new PathDiagnosticPiece(L, os.str()));
          }
          else
            PD.push_front(new PathDiagnosticPiece(L,
                              "Loop condition is false.  Exiting loop."));

          break;
        }

        case Stmt::WhileStmtClass:
        case Stmt::ForStmtClass: {

          if (*(Src->succ_begin()+1) == Dst) {

            std::ostringstream os;

            os << "Loop condition is false. Execution continues on line "
               << SMgr.getLogicalLineNumber(GetStmt(Dst)->getLocStart()) << '.';

            PD.push_front(new PathDiagnosticPiece(L, os.str()));
          }
          else
            PD.push_front(new PathDiagnosticPiece(L,
                            "Loop condition is true.  Entering loop body."));

          break;
        }

        case Stmt::IfStmtClass: {

          if (*(Src->succ_begin()+1) == Dst)
            PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
          else
            PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));

          break;
        }
      }
    }
    else
      if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode, *GTrim, *this))
        PD.push_front(piece);
  }
}

bool BugTypeCacheLocation::isCached(BugReport& R) {

  ExplodedNode<ValueState>* N = R.getEndNode();

  if (!N)
    return false;

  // Cache the location of the error.  Don't emit the same
  // warning for the same error type that occurs at the same program
  // location but along a different path.

  void* p = N->getLocation().getRawData();

  if (CachedErrors.count(p))
    return true;

  CachedErrors.insert(p);
  return false;
}

void BugReporter::EmitWarning(BugReport& R) {

  if (R.getBugType().isCached(R))
    return;

  llvm::OwningPtr<PathDiagnostic> D(new PathDiagnostic(R.getName()));
  GeneratePathDiagnostic(*D.get(), R);

  // Emit a full diagnostic for the path if we have a PathDiagnosticClient.

  if (PD && !D->empty()) {
    PD->HandlePathDiagnostic(D.take());
    return;
  }

  // We don't have a PathDiagnosticClient, but we can still emit a single
  // line diagnostic.  Determine the location.

  FullSourceLoc L = D->empty() ? R.getLocation(Ctx.getSourceManager())
                               : D->back()->getLocation();

  // Determine the range.

  const SourceRange *Beg, *End;

  if (!D->empty()) {
    Beg = D->back()->ranges_begin();
    End = D->back()->ranges_end();
  }
  else
    R.getRanges(Beg, End);

  if (PD) {
    PathDiagnosticPiece* piece = new PathDiagnosticPiece(L, R.getDescription());

    for ( ; Beg != End; ++Beg)
      piece->addRange(*Beg);

    D->push_back(piece);
    PD->HandlePathDiagnostic(D.take());
  }
  else {
    std::ostringstream os;
    os << "[CHECKER] ";

    if (D->empty())
      os << R.getDescription();
    else
      os << D->back()->getString();

    unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
                                              os.str().c_str());

    Diag.Report(L, ErrorDiag, NULL, 0, Beg, End - Beg);
  }
}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :    NFPluginLoader.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :
//    @Module           :    NFPluginLoader
//
// -------------------------------------------------------------------------

//#include <crtdbg.h>
#include <time.h>
#include <stdio.h>
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
#include "NFCActorManager.h"
#include "NFComm/Config/NFConfig.h"
#include "NFComm/NFCore/NFPlatform.h"
#include "boost/thread.hpp"

#pragma comment( lib, "DbgHelp" )
#if NF_PLATFORM == NF_PLATFORM_WIN

// Dumpļ
void CreateDumpFile(const std::string& strDumpFilePathName, EXCEPTION_POINTERS* pException)
{
    // Dumpļ
    HANDLE hDumpFile = CreateFile(strDumpFilePathName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // DumpϢ
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    dumpInfo.ExceptionPointers = pException;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ClientPointers = TRUE;

    // дDumpļ
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

    CloseHandle(hDumpFile);
}

// Unhandled ExceptionĻص
long ApplicationCrashHandler(EXCEPTION_POINTERS* pException)
{
    time_t t = time(0);
    char szDmupName[MAX_PATH];
    tm* ptm = localtime(&t);

    sprintf(szDmupName, "%d_%d_%d_%d_%d_%d.dmp",  ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    CreateDumpFile(szDmupName, pException);

    FatalAppExit(-1,  szDmupName);

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

void CloseXButton()
{
#if NF_PLATFORM == NF_PLATFORM_WIN

    HWND hWnd = GetConsoleWindow();
    if(hWnd)
    {
        HMENU hMenu = GetSystemMenu(hWnd, FALSE);
        EnableMenuItem(hMenu, SC_CLOSE, MF_DISABLED | MF_BYCOMMAND);
    }

#endif
}

bool bExitApp = false;
boost::thread gThread;

void ThreadFunc()
{
    while ( !bExitApp )
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        std::string s;
        std::cin >> s;
        if ( 0 == stricmp( s.c_str(), "exit" ) )
        {
            bExitApp = true;
        }
    }
}

void CreateBackThread()
{
    gThread = boost::thread(boost::bind(&ThreadFunc));
    //std::cout << "CreateBackThread, thread ID = " << gThread.get_id() << std::endl;
}

void PrintfLogo()
{
#if NF_PLATFORM == NF_PLATFORM_WIN
    std::cout << "\n" << std::endl;

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    std::cout << "" << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "                 NoahFrame                  " << std::endl;
    std::cout << "     Copyright (c) 2011  kytoo              " << std::endl;
    std::cout << "             All rights reserved.           " << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "               www.yowoyo.com               " << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "\n" << std::endl;

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    std::cout << "\n" << std::endl;
#endif // NF_PLATFORM
}

unsigned long unStartTickTime = 0;
unsigned long unLastTickTime = 0;

#if NF_PLATFORM == NF_PLATFORM_WIN || NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_APPLE
int main()
#elif  NF_PLATFORM == NF_PLATFORM_ANDROID || NF_PLATFORM == NF_PLATFORM_APPLE_IOS

#endif
{
#if NF_PLATFORM == NF_PLATFORM_WIN
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
#endif
	NFCActorManager::GetSingletonPtr()->Init();
	NFCActorManager::GetSingletonPtr()->AfterInit();
    NFCActorManager::GetSingletonPtr()->CheckConfig();

    PrintfLogo();

    CloseXButton();
    CreateBackThread();

    unStartTickTime = ::NF_GetTickCount();
    unLastTickTime = unStartTickTime;

    while (!bExitApp)    //DEBUG汾RELEASE
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        while (true)
        {
            if (bExitApp)
            {
                break;
            }

			unsigned long unNowTickTime = ::NF_GetTickCount();
			float fStartedTime = float(unNowTickTime - unStartTickTime) / 1000;
			float fLastTime = float(unNowTickTime - unLastTickTime) / 1000;

			if (fStartedTime < 0.001f)
			{
				fStartedTime = 0.0f;
			}

#if NF_PLATFORM == NF_PLATFORM_WIN
            __try
            {
#endif
                NFCActorManager::GetSingletonPtr()->Execute(fLastTime, fStartedTime);
				unLastTickTime = unNowTickTime;
#if NF_PLATFORM == NF_PLATFORM_WIN
            }
            __except (ApplicationCrashHandler(GetExceptionInformation()))
            {
            }
#endif
        }
    }

	NFCActorManager::GetSingletonPtr()->BeforeShut();
	NFCActorManager::GetSingletonPtr()->Shut();

    NFCActorManager::GetSingletonPtr()->ReleaseInstance();

    return 0;
}
<commit_msg>fixed for CPU high[sleep]<commit_after>// -------------------------------------------------------------------------
//    @FileName         :    NFPluginLoader.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :
//    @Module           :    NFPluginLoader
//
// -------------------------------------------------------------------------

//#include <crtdbg.h>
#include <time.h>
#include <stdio.h>
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
#include "NFCActorManager.h"
#include "NFComm/Config/NFConfig.h"
#include "NFComm/NFCore/NFPlatform.h"
#include "boost/thread.hpp"

#pragma comment( lib, "DbgHelp" )
#if NF_PLATFORM == NF_PLATFORM_WIN

// Dumpļ
void CreateDumpFile(const std::string& strDumpFilePathName, EXCEPTION_POINTERS* pException)
{
    // Dumpļ
    HANDLE hDumpFile = CreateFile(strDumpFilePathName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // DumpϢ
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    dumpInfo.ExceptionPointers = pException;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ClientPointers = TRUE;

    // дDumpļ
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

    CloseHandle(hDumpFile);
}

// Unhandled ExceptionĻص
long ApplicationCrashHandler(EXCEPTION_POINTERS* pException)
{
    time_t t = time(0);
    char szDmupName[MAX_PATH];
    tm* ptm = localtime(&t);

    sprintf(szDmupName, "%d_%d_%d_%d_%d_%d.dmp",  ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    CreateDumpFile(szDmupName, pException);

    FatalAppExit(-1,  szDmupName);

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

void CloseXButton()
{
#if NF_PLATFORM == NF_PLATFORM_WIN

    HWND hWnd = GetConsoleWindow();
    if(hWnd)
    {
        HMENU hMenu = GetSystemMenu(hWnd, FALSE);
        EnableMenuItem(hMenu, SC_CLOSE, MF_DISABLED | MF_BYCOMMAND);
    }

#endif
}

bool bExitApp = false;
boost::thread gThread;

void ThreadFunc()
{
    while ( !bExitApp )
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        std::string s;
        std::cin >> s;
        if ( 0 == stricmp( s.c_str(), "exit" ) )
        {
            bExitApp = true;
        }
    }
}

void CreateBackThread()
{
    gThread = boost::thread(boost::bind(&ThreadFunc));
    //std::cout << "CreateBackThread, thread ID = " << gThread.get_id() << std::endl;
}

void PrintfLogo()
{
#if NF_PLATFORM == NF_PLATFORM_WIN
    std::cout << "\n" << std::endl;

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    std::cout << "" << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "                 NoahFrame                  " << std::endl;
    std::cout << "     Copyright (c) 2011  kytoo              " << std::endl;
    std::cout << "             All rights reserved.           " << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "               www.yowoyo.com               " << std::endl;
    std::cout << "                                            " << std::endl;
    std::cout << "\n" << std::endl;

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

    std::cout << "\n" << std::endl;
#endif // NF_PLATFORM
}

unsigned long unStartTickTime = 0;
unsigned long unLastTickTime = 0;

#if NF_PLATFORM == NF_PLATFORM_WIN || NF_PLATFORM == NF_PLATFORM_LINUX || NF_PLATFORM == NF_PLATFORM_APPLE
int main()
#elif  NF_PLATFORM == NF_PLATFORM_ANDROID || NF_PLATFORM == NF_PLATFORM_APPLE_IOS

#endif
{
#if NF_PLATFORM == NF_PLATFORM_WIN
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
#endif
	NFCActorManager::GetSingletonPtr()->Init();
	NFCActorManager::GetSingletonPtr()->AfterInit();
    NFCActorManager::GetSingletonPtr()->CheckConfig();

    PrintfLogo();

    CloseXButton();
    CreateBackThread();

    unStartTickTime = ::NF_GetTickCount();
    unLastTickTime = unStartTickTime;

    while (!bExitApp)    //DEBUG汾RELEASE
    {
        while (true)
        {
			std::this_thread::sleep_for(std::chrono::milliseconds(1000));

            if (bExitApp)
            {
                break;
            }

			unsigned long unNowTickTime = ::NF_GetTickCount();
			float fStartedTime = float(unNowTickTime - unStartTickTime) / 1000;
			float fLastTime = float(unNowTickTime - unLastTickTime) / 1000;

			if (fStartedTime < 0.001f)
			{
				fStartedTime = 0.0f;
			}

#if NF_PLATFORM == NF_PLATFORM_WIN
            __try
            {
#endif
                NFCActorManager::GetSingletonPtr()->Execute(fLastTime, fStartedTime);
				unLastTickTime = unNowTickTime;
#if NF_PLATFORM == NF_PLATFORM_WIN
            }
            __except (ApplicationCrashHandler(GetExceptionInformation()))
            {
            }
#endif
        }
    }

	NFCActorManager::GetSingletonPtr()->BeforeShut();
	NFCActorManager::GetSingletonPtr()->Shut();

    NFCActorManager::GetSingletonPtr()->ReleaseInstance();

    return 0;
}
<|endoftext|>