<commit_before>#include "testing/testing.hpp"

#include "routing/routing_quality/waypoints.hpp"

using namespace routing_quality;

// Test on preferring better but longer roads should be grouped in this file.
namespace
{
// Secondary should be preferred against residential.
UNIT_TEST(RoutingQuality_RussiaMoscowTushino)
{
  TEST(CheckCarRoute({55.84398, 37.45018} /* start */, {55.85489, 37.43784} /* finish */,
                     {{{55.84343, 37.43949}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_TurkeyIzmirArea)
{
  TEST(CheckCarRoute({38.80146, 26.97696} /* start */, {39.0837, 26.90977} /* finish */,
                     {{{39.08146, 27.11798}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_BosniaAndHerzegovina)
{
  TEST(CheckCarRoute({42.71401, 18.30412} /* start */, {42.95101, 18.08966} /* finish */,
                     {{{42.88222,17.9919}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_CzechiaPrague)
{
  TEST(CheckCarRoute({50.10159, 14.43324} /* start */, {50.20976, 14.43361} /* finish */,
                     {{{50.15078, 14.49205}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_FinlandHelsinki)
{
  TEST(CheckCarRoute({60.16741, 24.94255} /* start */, {64.13182, 28.38784} /* finish */,
                     {{{60.95453, 25.6951}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_USAOklahoma)
{
  TEST(CheckCarRoute({35.39166, -97.55402} /* start */, {35.38452, -97.5742} /* finish */,
                     {{{35.39912, -97.57622}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_IranSouth)
{
  TEST(CheckCarRoute({32.45088, 51.76419} /* start */, {32.97067, 51.50399} /* finish */,
                     {{{32.67021, 51.64323}, {32.68752, 51.63387}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_EindhovenNetherlands)
{
  TEST(CheckCarRoute({50.91974, 5.33535} /* start */, {51.92532, 5.49066} /* finish */,
                     {{{51.42016, 5.42881}, {51.44316, 5.42723}, {51.50230, 5.47485}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_GeteborgasSweden)
{
  TEST(CheckCarRoute({57.77064, 11.88079} /* start */, {57.71231, 11.93157} /* finish */,
                     {{{57.74912, 11.87343}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_CigilTurkey)
{
  TEST(CheckCarRoute({38.48175, 27.12952} /* start */, {38.47558, 27.06765} /* finish */,
                     {{{38.4898049, 27.1016266}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_KatowicePoland)
{
  TEST(CheckCarRoute({50.37282, 18.75667} /* start */, {50.83499, 19.14612} /* finish */,
                     {{{50.422229, 19.04746}, {50.48831, 19.21423}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_KrasnoyarskBratsk)
{
  TEST(CheckCarRoute({56.009, 92.873} /* start */, {56.163, 101.611} /* finish */,
                     {{{55.89285, 97.99953}, {54.59928, 100.60402}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_VoronezhSochi)
{
  TEST(CheckCarRoute({51.65487, 39.21293} /* start */, {43.58547, 39.72311} /* finish */,
                     {{{46.14169, 39.85306}, {45.17069, 39.10869},
                       {45.02157, 39.12510}, {44.54344, 38.95853}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_BerlinkaWarsawPoland)
{
  TEST(CheckCarRoute({54.41616, 20.05675} /* start */, {52.18937, 20.94026} /* finish */,
                     {{{54.24278, 19.66106}, {54.13679, 19.45166},
                       {54.06452, 19.62416}, {53.69769, 19.98204},
                       {53.11194, 20.40002}, {52.62966, 20.38488}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_LenOblBadPaving)
{
  TEST(CheckCarRoute({60.23884, 29.71603} /* start */, {60.29083, 29.80333} /* finish */,
                     {{{60.2510134, 29.790209}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_MosOblBadPaving)
{
  TEST(CheckCarRoute({55.93849, 36.02792} /* start */, {55.93566, 36.05074} /* finish */,
                     {{{55.92321, 36.04630}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_LatviaUnpaved)
{
  TEST(CheckCarRoute({56.62992, 25.77175} /* start */, {56.61453, 25.78400} /* finish */,
                     {{{56.62377, 25.81015}, {56.61755, 25.80894}}} /* reference track */),
       ());
}
}  // namespace
<commit_msg>[routing] routing quality tests fixes.<commit_after>#include "testing/testing.hpp"

#include "routing/routing_quality/waypoints.hpp"

using namespace routing_quality;

// Test on preferring better but longer roads should be grouped in this file.
namespace
{
// Secondary should be preferred against residential.
UNIT_TEST(RoutingQuality_RussiaMoscowTushino)
{
  TEST(CheckCarRoute({55.84398, 37.45018} /* start */, {55.85489, 37.43784} /* finish */,
                     {{{55.84343, 37.43949}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_TurkeyIzmirArea)
{
  TEST(CheckCarRoute({38.80146, 26.97696} /* start */, {39.0837, 26.90977} /* finish */,
                     {{{39.08146, 27.11798}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_BosniaAndHerzegovina)
{
  TEST(CheckCarRoute({42.71401, 18.30412} /* start */, {42.95101, 18.08966} /* finish */,
                     {{{42.88222,17.9919}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_CzechiaPrague)
{
  TEST(CheckCarRoute({50.10159, 14.43324} /* start */, {50.20976, 14.43361} /* finish */,
                     {{{50.15078, 14.49205}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_FinlandHelsinki)
{
  TEST(CheckCarRoute({60.16741, 24.94255} /* start */, {64.13182, 28.38784} /* finish */,
                     {{{60.95453, 25.6951}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_USAOklahoma)
{
  TEST(CheckCarRoute({35.39166, -97.55402} /* start */, {35.38452, -97.5742} /* finish */,
                     {{{35.39912, -97.57622}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_IranSouth)
{
  TEST(CheckCarRoute({32.45088, 51.76419} /* start */, {32.97067, 51.50399} /* finish */,
                     {{{32.67021, 51.64323}, {32.68752, 51.63387}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_EindhovenNetherlands)
{
  TEST(CheckCarRoute({50.91974, 5.33535} /* start */, {51.92532, 5.49066} /* finish */,
                     {{{51.42016, 5.42881}, {51.44316, 5.42723}, {51.50230, 5.47485}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_GeteborgasSweden)
{
  TEST(CheckCarRoute({57.77064, 11.88079} /* start */, {57.71231, 11.93157} /* finish */,
                     {{{57.74912, 11.87343}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_CigilTurkey)
{
  TEST(CheckCarRoute({38.48175, 27.12952} /* start */, {38.47558, 27.06765} /* finish */,
                     {{{38.4898049, 27.1016266}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_KatowicePoland)
{
  TEST(CheckCarRoute({50.37282, 18.75667} /* start */, {50.83499, 19.14612} /* finish */,
                     {{{50.422229, 19.04746}, {50.48831, 19.21423}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_KrasnoyarskBratsk)
{
  TEST(CheckCarRoute({56.009, 92.873} /* start */, {56.163, 101.611} /* finish */,
                     {{{55.89285, 97.99953}, {54.59928, 100.60402}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_VoronezhSochi)
{
  TEST(CheckCarRoute({51.65487, 39.21293} /* start */, {43.58547, 39.72311} /* finish */,
                     {{{46.14169, 39.85306}, {45.17069, 39.10869},
                       {45.02157, 39.12510}, {44.54344, 38.95853}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_BerlinkaWarsawPoland)
{
  TEST(CheckCarRoute({54.41616, 20.05675} /* start */, {52.18937, 20.94026} /* finish */,
                     {{{54.24278, 19.66106}, {54.13679, 19.45166},
                       {54.06452, 19.62416}, {53.69769, 19.98204},
                       {53.11194, 20.40002}, {52.62966, 20.38488}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_LenOblBadPaving)
{
  TEST(CheckCarRoute({60.23884, 29.71603} /* start */, {60.29083, 29.80333} /* finish */,
                     {{{60.2510134, 29.790209}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_MosOblBadPaving)
{
  TEST(CheckCarRoute({55.93849, 36.02792} /* start */, {55.93567, 36.0533} /* finish */,
                     {{{55.92321, 36.04630}}} /* reference track */),
       ());
}

UNIT_TEST(RoutingQuality_LatviaUnpaved)
{
  TEST(CheckCarRoute({56.62992, 25.77175} /* start */, {56.61453, 25.78400} /* finish */,
                     {{{56.62377, 25.81015}, {56.61755, 25.80894}}} /* reference track */),
       ());
}
}  // namespace
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_EXECUTION_CONTEXT_HPP_
#define _QI_EXECUTION_CONTEXT_HPP_

#include <boost/function.hpp>
#include <qi/clock.hpp>
#include <qi/api.hpp>

namespace qi
{

template <typename T>
class Future;

namespace detail
{

  // This class is kind of a hack to deprecate the old versions of async/post etc without deprecating the correct use of
  // the new ones. This class is just a strong alias to boost::function
  template <typename T>
  struct Function : boost::function<T>
  {
    using boost::function<T>::function;
  };

}

class QI_API ExecutionContext
{
public:
  virtual ~ExecutionContext() {}

  // DEPRECATED STUFF
  /// call a callback asynchronously to be executed on tp
  /// @deprecated since 2.5
  QI_API_DEPRECATED virtual qi::Future<void> async(const boost::function<void()>& callback,
      qi::SteadyClockTimePoint tp) = 0;
  /// call a callback asynchronously to be executed in delay
  /// @deprecated since 2.5
  QI_API_DEPRECATED virtual qi::Future<void> async(const boost::function<void()>& callback,
      qi::Duration delay) = 0;
  /// call a callback asynchronously to be executed in delay
  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED typename boost::disable_if<boost::is_same<R, void>,
                              qi::Future<R> >::type
      async(const boost::function<R()>& callback,
          qi::Duration delay);
  /// call a callback asynchronously to be executed on tp
  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED typename boost::disable_if<boost::is_same<R, void>,
                              qi::Future<R> >::type
      async(const boost::function<R()>& callback, qi::SteadyClockTimePoint tp);

  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED qi::Future<R> async(const detail::Function<R()>& callback)
  {
    return asyncDelay(callback, qi::Duration(0));
  }
  // END OF DEPRECATED STUFF

  /// post a callback to be executed as soon as possible
  template <typename F>
  void post(F&& callback);
  /// call a callback asynchronously to be executed on tp
  template <typename F>
  auto asyncAt(F&& callback, qi::SteadyClockTimePoint tp) -> qi::Future<typename std::decay<decltype(callback())>::type>;
  /// call a callback asynchronously to be executed in delay
  template <typename F>
  auto asyncDelay(F&& callback, qi::Duration delay) -> qi::Future<typename std::decay<decltype(callback())>::type>;

  template <typename F>
  auto async(F&& callback) -> decltype(asyncDelay(std::forward<F>(callback), qi::Duration(0)))
  {
    return asyncDelay(std::forward<F>(callback), qi::Duration(0));
  }

  /// return true if the current thread is in this context
  virtual bool isInThisContext() = 0;

protected:
  virtual void postImpl(boost::function<void()> callback) = 0;
  virtual qi::Future<void> asyncAtImpl(boost::function<void()> cb, qi::SteadyClockTimePoint tp) = 0;
  virtual qi::Future<void> asyncDelayImpl(boost::function<void()> cb, qi::Duration delay) = 0;
};

}

#include <qi/detail/future_fwd.hpp>

namespace qi
{

namespace detail
{

template <typename T>
class DelayedPromise: public Promise<T>
{
public:
  void setup(boost::function<void (qi::Promise<T>)> cancelCallback, FutureCallbackType async = FutureCallbackType_Async)
  {
    Promise<T>::setup(cancelCallback, async);
  }
};

template <typename R>
void setValue(qi::Promise<R>& p, const boost::function<R()>& f)
{
  p.setValue(f());
}

template <>
inline void setValue<void>(qi::Promise<void>& p, const boost::function<void()>& f)
{
  f();
  p.setValue(0);
}

template <typename R>
void callAndSet(qi::Promise<R> p, boost::function<R()> f)
{
  try
  {
    setValue<R>(p, f);
  }
  catch (const std::exception& e)
  {
    p.setError(e.what());
  }
  catch(...)
  {
    p.setError("unknown exception");
  }
}
template <typename R>
void checkCanceled(qi::Future<void> f, qi::Promise<R> p)
{
  if (f.wait() == FutureState_Canceled)
    p.setCanceled();
  // Nothing to do for other states.
}

}

template <typename R>
typename boost::disable_if<boost::is_same<R, void>,
                            qi::Future<R> >::type
    ExecutionContext::async(const boost::function<R()>& callback,
                            qi::Duration delay)
{
  detail::DelayedPromise<R> promise;
  qi::Future<void> f = async(boost::function<void()>(boost::bind(
                                 detail::callAndSet<R>, promise, callback)),
                             delay);
  promise.setup(
      boost::bind(&detail::futureCancelAdapter<void>,
                  boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<R>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename R>
typename boost::disable_if<boost::is_same<R, void>,
                            qi::Future<R> >::type
    ExecutionContext::async(const boost::function<R()>& callback,
                            qi::SteadyClockTimePoint tp)
{
  detail::DelayedPromise<R> promise;
  qi::Future<void> f = async(boost::function<void()>(boost::bind(
                                 detail::callAndSet<R>, promise, callback)),
                             tp);
  promise.setup(
      boost::bind(&detail::futureCancelAdapter<void>,
                  boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<R>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename F>
void ExecutionContext::post(F&& callback)
{
  postImpl(std::forward<F>(callback));
}

template <typename ReturnType, typename Callback>
struct ToPost
{
  detail::DelayedPromise<ReturnType> promise;
  Callback callback;

  ToPost(Callback cb) :
    callback(std::move(cb))
  {}

  void operator()()
  {
    detail::callAndSet<ReturnType>(std::move(promise), std::move(callback));
  }
};

template <typename F>
auto ExecutionContext::asyncAt(F&& callback, qi::SteadyClockTimePoint tp) -> qi::Future<typename std::decay<decltype(callback())>::type>
{
  using ReturnType = typename std::decay<decltype(callback())>::type;

  ToPost<ReturnType, typename std::decay<F>::type> topost(std::move(callback));
  auto promise = topost.promise;
  qi::Future<void> f = asyncAtImpl(std::move(topost), tp);
  promise.setup(boost::bind(&detail::futureCancelAdapter<void>,
                            boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<ReturnType>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename F>
auto ExecutionContext::asyncDelay(F&& callback, qi::Duration delay) -> qi::Future<typename std::decay<decltype(callback())>::type>
{
  using ReturnType = typename std::decay<decltype(callback())>::type;

  ToPost<ReturnType, typename std::decay<F>::type> topost(std::move(callback));
  auto promise = topost.promise;
  qi::Future<void> f = asyncDelayImpl(std::move(topost), delay);
  promise.setup(boost::bind(&detail::futureCancelAdapter<void>,
                            boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<ReturnType>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}
}

#endif
<commit_msg>Fixed: vs2013 does not manage using directive with parent type constr.<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_EXECUTION_CONTEXT_HPP_
#define _QI_EXECUTION_CONTEXT_HPP_

#include <boost/function.hpp>
#include <qi/clock.hpp>
#include <qi/api.hpp>

namespace qi
{

template <typename T>
class Future;

namespace detail
{

  // This class is kind of a hack to deprecate the old versions of async/post etc without deprecating the correct use of
  // the new ones. This class is just a strong alias to boost::function
  template <typename T>
  struct Function : boost::function<T>
  {
    template<class... Args>
    Function(Args&&... args)
      : boost::function<T>(std::forward<Args>(args)...)
    {}
  };

}

class QI_API ExecutionContext
{
public:
  virtual ~ExecutionContext() {}

  // DEPRECATED STUFF
  /// call a callback asynchronously to be executed on tp
  /// @deprecated since 2.5
  QI_API_DEPRECATED virtual qi::Future<void> async(const boost::function<void()>& callback,
      qi::SteadyClockTimePoint tp) = 0;
  /// call a callback asynchronously to be executed in delay
  /// @deprecated since 2.5
  QI_API_DEPRECATED virtual qi::Future<void> async(const boost::function<void()>& callback,
      qi::Duration delay) = 0;
  /// call a callback asynchronously to be executed in delay
  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED typename boost::disable_if<boost::is_same<R, void>,
                              qi::Future<R> >::type
      async(const boost::function<R()>& callback,
          qi::Duration delay);
  /// call a callback asynchronously to be executed on tp
  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED typename boost::disable_if<boost::is_same<R, void>,
                              qi::Future<R> >::type
      async(const boost::function<R()>& callback, qi::SteadyClockTimePoint tp);

  /// @deprecated since 2.5
  template <typename R>
  QI_API_DEPRECATED qi::Future<R> async(const detail::Function<R()>& callback)
  {
    return asyncDelay(callback, qi::Duration(0));
  }
  // END OF DEPRECATED STUFF

  /// post a callback to be executed as soon as possible
  template <typename F>
  void post(F&& callback);
  /// call a callback asynchronously to be executed on tp
  template <typename F>
  auto asyncAt(F&& callback, qi::SteadyClockTimePoint tp) -> qi::Future<typename std::decay<decltype(callback())>::type>;
  /// call a callback asynchronously to be executed in delay
  template <typename F>
  auto asyncDelay(F&& callback, qi::Duration delay) -> qi::Future<typename std::decay<decltype(callback())>::type>;

  template <typename F>
  auto async(F&& callback) -> decltype(asyncDelay(std::forward<F>(callback), qi::Duration(0)))
  {
    return asyncDelay(std::forward<F>(callback), qi::Duration(0));
  }

  /// return true if the current thread is in this context
  virtual bool isInThisContext() = 0;

protected:
  virtual void postImpl(boost::function<void()> callback) = 0;
  virtual qi::Future<void> asyncAtImpl(boost::function<void()> cb, qi::SteadyClockTimePoint tp) = 0;
  virtual qi::Future<void> asyncDelayImpl(boost::function<void()> cb, qi::Duration delay) = 0;
};

}

#include <qi/detail/future_fwd.hpp>

namespace qi
{

namespace detail
{

template <typename T>
class DelayedPromise: public Promise<T>
{
public:
  void setup(boost::function<void (qi::Promise<T>)> cancelCallback, FutureCallbackType async = FutureCallbackType_Async)
  {
    Promise<T>::setup(cancelCallback, async);
  }
};

template <typename R>
void setValue(qi::Promise<R>& p, const boost::function<R()>& f)
{
  p.setValue(f());
}

template <>
inline void setValue<void>(qi::Promise<void>& p, const boost::function<void()>& f)
{
  f();
  p.setValue(0);
}

template <typename R>
void callAndSet(qi::Promise<R> p, boost::function<R()> f)
{
  try
  {
    setValue<R>(p, f);
  }
  catch (const std::exception& e)
  {
    p.setError(e.what());
  }
  catch(...)
  {
    p.setError("unknown exception");
  }
}
template <typename R>
void checkCanceled(qi::Future<void> f, qi::Promise<R> p)
{
  if (f.wait() == FutureState_Canceled)
    p.setCanceled();
  // Nothing to do for other states.
}

}

template <typename R>
typename boost::disable_if<boost::is_same<R, void>,
                            qi::Future<R> >::type
    ExecutionContext::async(const boost::function<R()>& callback,
                            qi::Duration delay)
{
  detail::DelayedPromise<R> promise;
  qi::Future<void> f = async(boost::function<void()>(boost::bind(
                                 detail::callAndSet<R>, promise, callback)),
                             delay);
  promise.setup(
      boost::bind(&detail::futureCancelAdapter<void>,
                  boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<R>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename R>
typename boost::disable_if<boost::is_same<R, void>,
                            qi::Future<R> >::type
    ExecutionContext::async(const boost::function<R()>& callback,
                            qi::SteadyClockTimePoint tp)
{
  detail::DelayedPromise<R> promise;
  qi::Future<void> f = async(boost::function<void()>(boost::bind(
                                 detail::callAndSet<R>, promise, callback)),
                             tp);
  promise.setup(
      boost::bind(&detail::futureCancelAdapter<void>,
                  boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<R>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename F>
void ExecutionContext::post(F&& callback)
{
  postImpl(std::forward<F>(callback));
}

template <typename ReturnType, typename Callback>
struct ToPost
{
  detail::DelayedPromise<ReturnType> promise;
  Callback callback;

  ToPost(Callback cb) :
    callback(std::move(cb))
  {}

  void operator()()
  {
    detail::callAndSet<ReturnType>(std::move(promise), std::move(callback));
  }
};

template <typename F>
auto ExecutionContext::asyncAt(F&& callback, qi::SteadyClockTimePoint tp) -> qi::Future<typename std::decay<decltype(callback())>::type>
{
  using ReturnType = typename std::decay<decltype(callback())>::type;

  ToPost<ReturnType, typename std::decay<F>::type> topost(std::move(callback));
  auto promise = topost.promise;
  qi::Future<void> f = asyncAtImpl(std::move(topost), tp);
  promise.setup(boost::bind(&detail::futureCancelAdapter<void>,
                            boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<ReturnType>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}

template <typename F>
auto ExecutionContext::asyncDelay(F&& callback, qi::Duration delay) -> qi::Future<typename std::decay<decltype(callback())>::type>
{
  using ReturnType = typename std::decay<decltype(callback())>::type;

  ToPost<ReturnType, typename std::decay<F>::type> topost(std::move(callback));
  auto promise = topost.promise;
  qi::Future<void> f = asyncDelayImpl(std::move(topost), delay);
  promise.setup(boost::bind(&detail::futureCancelAdapter<void>,
                            boost::weak_ptr<detail::FutureBaseTyped<void> >(f.impl())));
  f.connect(boost::bind(&detail::checkCanceled<ReturnType>, _1, promise), FutureCallbackType_Sync);
  return promise.future();
}
}

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2010 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include "libforestdb/forestdb.h"
#include "common.h"
#include "internal_types.h"
#include "btree_var_kv_ops.h"
#include "hbtrie.h"
#include "fdb_internal.h"

#include "memleak.h"

#ifdef __DEBUG
#ifndef __DEBUG_FDB
    #undef DBG
    #undef DBGCMD
    #undef DBGSW
    #define DBG(...)
    #define DBGCMD(...)
    #define DBGSW(n, ...)
#endif
#endif

LIBFDB_API
fdb_status fdb_get_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen,
                      void **value_out, size_t *valuelen_out)
{
    fdb_doc *doc = NULL;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        value_out == NULL || valuelen_out == NULL ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, NULL, 0);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_get_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_get(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        if (doc) {
            fdb_doc_free(doc);
        }
        return fs;
    }

    *value_out = doc->body;
    *valuelen_out = doc->bodylen;
    if (doc->key) free(doc->key);
    if (doc->meta) free(doc->meta);
    free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_set_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen,
                      const void *value, size_t valuelen)
{
    fdb_doc *doc;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, value, valuelen);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_set_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_set(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        if (doc) {
            fdb_doc_free(doc);
        }
        return fs;
    }
    fdb_doc_free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_del_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen)
{
    fdb_doc *doc;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, NULL, 0);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_del_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_del(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        fdb_doc_free(doc);
        return fs;
    }
    fdb_doc_free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_free_block(void *ptr)
{
    free(ptr);
    return FDB_RESULT_SUCCESS;
}

<commit_msg>Protect api_wrappers from INVALID_HANDLE error<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2010 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include "libforestdb/forestdb.h"
#include "common.h"
#include "internal_types.h"
#include "btree_var_kv_ops.h"
#include "hbtrie.h"
#include "fdb_internal.h"

#include "memleak.h"

#ifdef __DEBUG
#ifndef __DEBUG_FDB
    #undef DBG
    #undef DBGCMD
    #undef DBGSW
    #define DBG(...)
    #define DBGCMD(...)
    #define DBGSW(n, ...)
#endif
#endif

LIBFDB_API
fdb_status fdb_get_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen,
                      void **value_out, size_t *valuelen_out)
{
    if (!handle) {
        return FDB_RESULT_INVALID_HANDLE;
    }

    fdb_doc *doc = NULL;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        value_out == NULL || valuelen_out == NULL ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, NULL, 0);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_get_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_get(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        if (doc) {
            fdb_doc_free(doc);
        }
        return fs;
    }

    *value_out = doc->body;
    *valuelen_out = doc->bodylen;
    if (doc->key) free(doc->key);
    if (doc->meta) free(doc->meta);
    free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_set_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen,
                      const void *value, size_t valuelen)
{
    if (!handle) {
        return FDB_RESULT_INVALID_HANDLE;
    }

    fdb_doc *doc;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, value, valuelen);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_set_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_set(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        if (doc) {
            fdb_doc_free(doc);
        }
        return fs;
    }
    fdb_doc_free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_del_kv(FdbKvsHandle *handle,
                      const void *key, size_t keylen)
{
    if (!handle) {
        return FDB_RESULT_INVALID_HANDLE;
    }

    fdb_doc *doc;
    fdb_status fs;

    if (key == NULL || keylen == 0 || keylen > FDB_MAX_KEYLEN ||
        (handle->kvs_config.custom_cmp &&
            keylen > handle->config.blocksize - HBTRIE_HEADROOM)) {
        return FDB_RESULT_INVALID_ARGS;
    }

    fs = fdb_doc_create(&doc, key, keylen, NULL, 0, NULL, 0);
    if (fs != FDB_RESULT_SUCCESS) { // LCOV_EXCL_START
        if (doc) {
            fdb_doc_free(doc);
        }
        fdb_log(&handle->log_callback, fs,
                "Warning: Failed to allocate fdb_doc instance for key '%s' in "
                "fdb_del_kv API.", (const char *)key);
        return fs;
    } // LCOV_EXCL_STOP

    fs = fdb_del(handle, doc);
    if (fs != FDB_RESULT_SUCCESS) {
        fdb_doc_free(doc);
        return fs;
    }
    fdb_doc_free(doc);

    return fs;
}

LIBFDB_API
fdb_status fdb_free_block(void *ptr)
{
    free(ptr);
    return FDB_RESULT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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
 *
 */

#include "contexttyperegistryinfo.h"
#include "logging.h"
#include "loggingfeatures.h"
#include <QMutex>
#include <QMutexLocker>
#include <QCoreApplication>
#include "nanoxml.h"

ContextTypeRegistryInfo* ContextTypeRegistryInfo::registryInstance = NULL;

/* Public */

ContextTypeRegistryInfo* ContextTypeRegistryInfo::instance()
{
    static QMutex mutex;
    QMutexLocker locker(&mutex);
    if (! registryInstance) {
        contextDebug() << F_TYPES << "Creating ContextTypeRegistryInfo instance";
        registryInstance = new ContextTypeRegistryInfo;

        // Move the backend to the main thread
        registryInstance->moveToThread(QCoreApplication::instance()->thread());
    }

    return registryInstance;
}

/// Returns the full path to the registry directory. Takes the
/// \c CONTEXT_TYPES env variable into account.
QString ContextTypeRegistryInfo::registryPath()
{
    const char *regpath = getenv("CONTEXT_TYPES");
    if (! regpath)
        regpath = DEFAULT_CONTEXT_TYPES;

    return QString(regpath);
}

/// Returns the full path to the core property declaration file. Takes
/// the \c CONTEXT_CORE_TYPES env variable into account.
QString ContextTypeRegistryInfo::coreTypesPath()
{
    const char *corepath = getenv("CONTEXT_CORE_TYPES");
    if (! corepath)
        corepath = DEFAULT_CONTEXT_CORE_TYPES;

    return QString(corepath);
}

/* Private */

ContextTypeRegistryInfo::ContextTypeRegistryInfo()
{
    contextDebug() << F_TYPES << "Reading core types from:" << ContextTypeRegistryInfo::coreTypesPath();
    NanoXml parser(ContextTypeRegistryInfo::coreTypesPath());
    if (parser.didFail())
        contextWarning() << F_TYPES << "Reading core types failed, parsing error";
    else
        coreTree = parser.result();
}
<commit_msg>Revert "Read core types in constructor."<commit_after>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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
 *
 */

#include "contexttyperegistryinfo.h"
#include "logging.h"
#include "loggingfeatures.h"
#include <QMutex>
#include <QMutexLocker>
#include <QCoreApplication>
#include "nanoxml.h"

ContextTypeRegistryInfo* ContextTypeRegistryInfo::registryInstance = NULL;

/* Public */

ContextTypeRegistryInfo* ContextTypeRegistryInfo::instance()
{
    static QMutex mutex;
    QMutexLocker locker(&mutex);
    if (! registryInstance) {
        contextDebug() << F_TYPES << "Creating ContextTypeRegistryInfo instance";
        registryInstance = new ContextTypeRegistryInfo;

        // Move the backend to the main thread
        registryInstance->moveToThread(QCoreApplication::instance()->thread());
    }

    return registryInstance;
}

/// Returns the full path to the registry directory. Takes the
/// \c CONTEXT_TYPES env variable into account.
QString ContextTypeRegistryInfo::registryPath()
{
    const char *regpath = getenv("CONTEXT_TYPES");
    if (! regpath)
        regpath = DEFAULT_CONTEXT_TYPES;

    return QString(regpath);
}

/// Returns the full path to the core property declaration file. Takes
/// the \c CONTEXT_CORE_TYPES env variable into account.
QString ContextTypeRegistryInfo::coreTypesPath()
{
    const char *corepath = getenv("CONTEXT_CORE_TYPES");
    if (! corepath)
        corepath = DEFAULT_CONTEXT_CORE_TYPES;

    return QString(corepath);
}

/* Private */

ContextTypeRegistryInfo::ContextTypeRegistryInfo()
{
}
<|endoftext|>


<commit_before>#include "resizeHandler.h"

#include <algorithm>

ResizeHandler::ResizeHandler(
		NodeElement* const resizingNode
		, ElementImpl* const elementImpl
		)
	: mResizingNode(resizingNode)
	, mElementImpl(elementImpl)
{
}

void ResizeHandler::resize(QRectF newContents, QPointF newPos) const
{
	newContents.moveTo(0, 0);

	sortChildrenIfNeeded();
	gripeIfMinimizesToChildrenContainer(newContents);

	QRectF con = newContents;
	if (!mResizingNode->isFolded()) {
		resizeAccordingToChildren(newContents, newPos);
	}
	normalizeSize(newContents);

	newContents.moveTo(newPos);

	mResizingNode->setGeometry(newContents);
	mResizingNode->storeGeometry();

	parentResizeCall();

	/*
	if (SettingsManager::value("ActivateGrid").toBool()) {
		mResizingNode->alignToGrid();
	}
	*/
}

qreal ResizeHandler::maxChildWidth() const
{
	qreal maxChildWidthValue = 0;

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem) {
			continue;
		}

		maxChildWidthValue = qMax(maxChildWidthValue, curItem->contentsRect().width());
	}
	if (maxChildWidthValue == 0) {
		maxChildWidthValue = mResizingNode->childrenBoundingRect().width();
	}

	return maxChildWidthValue;
}

void ResizeHandler::sortChildrenIfNeeded() const
{
	if (!mElementImpl->isSortingContainer()) {
		return;
	}

	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();
	qreal curChildY = sizeOfForestalling + mTitlePadding;
	qreal const maxChildWidthValue = maxChildWidth();

	foreach (QGraphicsItem* const childItem, mResizingNode->childItems()) {
		QGraphicsRectItem* const placeholder = mResizingNode->placeholder();

		if(placeholder != NULL && childItem == placeholder) {
			QRectF const rect(sizeOfForestalling, curChildY,
					maxChildWidthValue, placeholder->rect().height());
			placeholder->setRect(rect);
			curChildY += placeholder->rect().height() + mChildSpacing;
		}

		NodeElement* const curItem = dynamic_cast<NodeElement* const>(childItem);
		if (!curItem) {
			continue;
		}

		qreal const necessaryWidth =
				mElementImpl->maximizesChildren()
				? maxChildWidthValue
				: curItem->contentsRect().width();
		QRectF const rect(sizeOfForestalling, curChildY, necessaryWidth, curItem->contentsRect().height());

		curItem->setGeometry(rect);
		curItem->storeGeometry();
		curChildY += curItem->contentsRect().height() + mElementImpl->sizeOfChildrenForestalling() + mChildSpacing;
	}
}

void ResizeHandler::gripeIfMinimizesToChildrenContainer(QRectF& contents) const
{
	if (mElementImpl->minimizesToChildren()) {
		contents = QRectF();
	}
}

void ResizeHandler::parentResizeCall() const
{
	NodeElement* const parItem = dynamic_cast<NodeElement* const>(mResizingNode->parentItem());
	if (parItem) {
		ResizeHandler const handler(parItem, parItem->elementImpl());
		handler.resize(parItem->contentsRect(), parItem->pos());
	}
}

void ResizeHandler::normalizeSize(QRectF& newContents) const
{
	if (newContents.width() < mMinSize) {
		newContents.setWidth(mResizingNode->foldedContentsRect().width());
	}

	if (newContents.height() < mMinSize) {
		newContents.setHeight(mResizingNode->foldedContentsRect().height());
	}
}

void ResizeHandler::resizeAccordingToChildren(QRectF& newContents, QPointF& newPos) const
{
	/*
	* AAAA!!! Who knows why is this code existed????!!!
	*
	foreach (QGraphicsItem *childItem, childItems()) {
		NodeElement* curItem = dynamic_cast<NodeElement*>(childItem);
		if (curItem && curItem->isPort() && newContents != mContents) {
			curItem->resizeChild(newContents, mContents);
		}
	}
	*/

	/// Vector of minimum negative XY child deflection from top left corner.
	QPointF const childDeflectionVector = childDeflection();

	moveChildren(-childDeflectionVector);
	newPos += childDeflectionVector;

	newContents.setBottomRight(newContents.bottomRight() - childDeflectionVector);
	expandByChildren(newContents);
}

QPointF ResizeHandler::childDeflection() const
{
	QPointF childDeflectionVector = QPointF(0, 0);
	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		childDeflectionVector.setX(qMin(curItem->pos().x() - sizeOfForestalling, childDeflectionVector.x()));
		childDeflectionVector.setY(qMin(curItem->pos().y() - sizeOfForestalling, childDeflectionVector.y()));
	}

	return childDeflectionVector;
}

void ResizeHandler::printChildPos() const
{
	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		qDebug() << "child pos: " << curItem->pos();
	}
}

void ResizeHandler::moveChildren(QPointF const &shift) const
{
	qreal const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (QGraphicsItem* const childItem, mResizingNode->childItems()) {
		NodeElement* const curItem = dynamic_cast<NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		curItem->moveBy(shift.x(), shift.y());

		QPointF pos(qMax(curItem->pos().x(), sizeOfForestalling)
				, qMax(curItem->pos().y(), sizeOfForestalling));
		///returns object to the parent area
		curItem->setPos(pos);
	}
}

void ResizeHandler::expandByChildren(QRectF& contents) const
{
	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		QRectF curChildItemBoundingRect = childBoundingRect(childItem, contents);

		if (curChildItemBoundingRect.width() == 0 || curChildItemBoundingRect.height() == 0) {
			continue;
		}

		// it seems to be more appropriate to use childItem->pos() but it causes
		// bad behaviour when dropping one element to another
		curChildItemBoundingRect.translate(childItem->scenePos() - mResizingNode->scenePos());

		contents.setLeft(qMin(curChildItemBoundingRect.left() - sizeOfForestalling
						, contents.left()));
		contents.setRight(qMax(curChildItemBoundingRect.right() + sizeOfForestalling
						, contents.right()));
		contents.setTop(qMin(curChildItemBoundingRect.top() - sizeOfForestalling
						, contents.top()));
		contents.setBottom(qMax(curChildItemBoundingRect.bottom() + sizeOfForestalling
						, contents.bottom()));
	}
}

QRectF ResizeHandler::childBoundingRect(const QGraphicsItem* const childItem, QRectF const &contents) const
{
	QRectF boundingRect;

	if (childItem == mResizingNode->placeholder()) {
		boundingRect = childItem->boundingRect();

		int const sizeOfForestalling = mElementImpl->sizeOfForestalling();
		boundingRect.setLeft(contents.left() + sizeOfForestalling);
		boundingRect.setRight(contents.right() - sizeOfForestalling);

		return boundingRect;
	}

	const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
	if (curItem && !curItem->isPort()) {
		boundingRect = curItem->contentsRect();
	}

	return boundingRect;
}
<commit_msg>Grid alignment enable.<commit_after>#include "resizeHandler.h"

#include <algorithm>

ResizeHandler::ResizeHandler(
		NodeElement* const resizingNode
		, ElementImpl* const elementImpl
		)
	: mResizingNode(resizingNode)
	, mElementImpl(elementImpl)
{
}

void ResizeHandler::resize(QRectF newContents, QPointF newPos) const
{
	newContents.moveTo(0, 0);

	sortChildrenIfNeeded();
	gripeIfMinimizesToChildrenContainer(newContents);

	QRectF con = newContents;
	if (!mResizingNode->isFolded()) {
		resizeAccordingToChildren(newContents, newPos);
	}
	normalizeSize(newContents);

	newContents.moveTo(newPos);

	mResizingNode->setGeometry(newContents);

	if (SettingsManager::value("ActivateGrid").toBool()) {
		mResizingNode->alignToGrid();
	}

	mResizingNode->storeGeometry();

	parentResizeCall();
}

qreal ResizeHandler::maxChildWidth() const
{
	qreal maxChildWidthValue = 0;

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem) {
			continue;
		}

		maxChildWidthValue = qMax(maxChildWidthValue, curItem->contentsRect().width());
	}
	if (maxChildWidthValue == 0) {
		maxChildWidthValue = mResizingNode->childrenBoundingRect().width();
	}

	return maxChildWidthValue;
}

void ResizeHandler::sortChildrenIfNeeded() const
{
	if (!mElementImpl->isSortingContainer()) {
		return;
	}

	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();
	qreal curChildY = sizeOfForestalling + mTitlePadding;
	qreal const maxChildWidthValue = maxChildWidth();

	foreach (QGraphicsItem* const childItem, mResizingNode->childItems()) {
		QGraphicsRectItem* const placeholder = mResizingNode->placeholder();

		if(placeholder != NULL && childItem == placeholder) {
			QRectF const rect(sizeOfForestalling, curChildY,
					maxChildWidthValue, placeholder->rect().height());
			placeholder->setRect(rect);
			curChildY += placeholder->rect().height() + mChildSpacing;
		}

		NodeElement* const curItem = dynamic_cast<NodeElement* const>(childItem);
		if (!curItem) {
			continue;
		}

		qreal const necessaryWidth =
				mElementImpl->maximizesChildren()
				? maxChildWidthValue
				: curItem->contentsRect().width();
		QRectF const rect(sizeOfForestalling, curChildY, necessaryWidth, curItem->contentsRect().height());

		curItem->setGeometry(rect);
		curItem->storeGeometry();
		curChildY += curItem->contentsRect().height() + mElementImpl->sizeOfChildrenForestalling() + mChildSpacing;
	}
}

void ResizeHandler::gripeIfMinimizesToChildrenContainer(QRectF& contents) const
{
	if (mElementImpl->minimizesToChildren()) {
		contents = QRectF();
	}
}

void ResizeHandler::parentResizeCall() const
{
	NodeElement* const parItem = dynamic_cast<NodeElement* const>(mResizingNode->parentItem());
	if (parItem) {
		ResizeHandler const handler(parItem, parItem->elementImpl());
		handler.resize(parItem->contentsRect(), parItem->pos());
	}
}

void ResizeHandler::normalizeSize(QRectF& newContents) const
{
	if (newContents.width() < mMinSize) {
		newContents.setWidth(mResizingNode->foldedContentsRect().width());
	}

	if (newContents.height() < mMinSize) {
		newContents.setHeight(mResizingNode->foldedContentsRect().height());
	}
}

void ResizeHandler::resizeAccordingToChildren(QRectF& newContents, QPointF& newPos) const
{
	/*
	* AAAA!!! Who knows why is this code existed????!!!
	*
	foreach (QGraphicsItem *childItem, childItems()) {
		NodeElement* curItem = dynamic_cast<NodeElement*>(childItem);
		if (curItem && curItem->isPort() && newContents != mContents) {
			curItem->resizeChild(newContents, mContents);
		}
	}
	*/

	/// Vector of minimum negative XY child deflection from top left corner.
	QPointF const childDeflectionVector = childDeflection();

	moveChildren(-childDeflectionVector);
	newPos += childDeflectionVector;

	newContents.setBottomRight(newContents.bottomRight() - childDeflectionVector);
	expandByChildren(newContents);
}

QPointF ResizeHandler::childDeflection() const
{
	QPointF childDeflectionVector = QPointF(0, 0);
	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		childDeflectionVector.setX(qMin(curItem->pos().x() - sizeOfForestalling, childDeflectionVector.x()));
		childDeflectionVector.setY(qMin(curItem->pos().y() - sizeOfForestalling, childDeflectionVector.y()));
	}

	return childDeflectionVector;
}

void ResizeHandler::printChildPos() const
{
	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		qDebug() << "child pos: " << curItem->pos();
	}
}

void ResizeHandler::moveChildren(QPointF const &shift) const
{
	qreal const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (QGraphicsItem* const childItem, mResizingNode->childItems()) {
		NodeElement* const curItem = dynamic_cast<NodeElement* const>(childItem);
		if (!curItem || curItem->isPort()) {
			continue;
		}

		curItem->moveBy(shift.x(), shift.y());

		QPointF pos(qMax(curItem->pos().x(), sizeOfForestalling)
				, qMax(curItem->pos().y(), sizeOfForestalling));
		///returns object to the parent area
		curItem->setPos(pos);
	}
}

void ResizeHandler::expandByChildren(QRectF& contents) const
{
	int const sizeOfForestalling = mElementImpl->sizeOfForestalling();

	foreach (const QGraphicsItem* const childItem, mResizingNode->childItems()) {
		QRectF curChildItemBoundingRect = childBoundingRect(childItem, contents);

		if (curChildItemBoundingRect.width() == 0 || curChildItemBoundingRect.height() == 0) {
			continue;
		}

		// it seems to be more appropriate to use childItem->pos() but it causes
		// bad behaviour when dropping one element to another
		curChildItemBoundingRect.translate(childItem->scenePos() - mResizingNode->scenePos());

		contents.setLeft(qMin(curChildItemBoundingRect.left() - sizeOfForestalling
						, contents.left()));
		contents.setRight(qMax(curChildItemBoundingRect.right() + sizeOfForestalling
						, contents.right()));
		contents.setTop(qMin(curChildItemBoundingRect.top() - sizeOfForestalling
						, contents.top()));
		contents.setBottom(qMax(curChildItemBoundingRect.bottom() + sizeOfForestalling
						, contents.bottom()));
	}
}

QRectF ResizeHandler::childBoundingRect(const QGraphicsItem* const childItem, QRectF const &contents) const
{
	QRectF boundingRect;

	if (childItem == mResizingNode->placeholder()) {
		boundingRect = childItem->boundingRect();

		int const sizeOfForestalling = mElementImpl->sizeOfForestalling();
		boundingRect.setLeft(contents.left() + sizeOfForestalling);
		boundingRect.setRight(contents.right() - sizeOfForestalling);

		return boundingRect;
	}

	const NodeElement* const curItem = dynamic_cast<const NodeElement* const>(childItem);
	if (curItem && !curItem->isPort()) {
		boundingRect = curItem->contentsRect();
	}

	return boundingRect;
}
<|endoftext|>


<commit_before>#include <util/singleton.h>
#include <util/scheduler.h>
#include <util/timer.h>
#include <iostream>

#include <map>
#include <boost/thread.hpp>

using namespace std;

namespace izenelib{
namespace util{

class QueueTimer : public Timer
{
public:
    QueueTimer(void (*callback)(void *),
               void *arg,
               uint32_t due_time,
               uint32_t period)
            :callback_(callback),
             arg_(arg),
             due_time_(due_time),
             period_(period)
    {}

    bool start()
    {
        return Timer::start(due_time_, period_);
    }

    bool startNow()
    {
        return Timer::start(0, period_);
    }

    virtual void signaled()
    {
        callback_(arg_);
    }

private:
    void (*callback_)(void *);
    void *arg_;
    uint32_t due_time_;
    uint32_t period_;
};

struct ScheduleOP
{
    std::string name;
    uint32_t default_interval;
    uint32_t delay_start;
    boost::function<void (int)> callback;
    QueueTimer* timer;
    volatile bool running;
    volatile bool immediatly_running;
    boost::mutex jobmutex;
};

class SchedulerImpl
{
public:
    SchedulerImpl() {}

    virtual ~SchedulerImpl()
    {
        removeAllJobs();
    }

    void removeAllJobs()
    {
        boost::mutex::scoped_lock l(mutex_);
        for (std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.begin();
                itr != jobs_.end(); ++itr)
        {
            boost::shared_ptr<ScheduleOP> job = itr->second;
            if (job->timer)
            {
                job->timer->stop();
                delete job->timer;
                job->timer = NULL;
            }
            while (job->immediatly_running)
                cond_.wait(l);
        }
        jobs_.clear();
    }

    bool addJob(const string &name, uint32_t default_interval,
                uint32_t delay_start, const boost::function<void (int)>& func)
    {
        boost::mutex::scoped_lock l(mutex_);
        std::map<string, boost::shared_ptr<ScheduleOP> >::iterator find_itr = jobs_.find(name);
        if (find_itr != jobs_.end())
            return false;

        boost::shared_ptr<ScheduleOP> newjob(new ScheduleOP());
        newjob->name = name;
        newjob->default_interval = default_interval;
        newjob->delay_start = delay_start;
        newjob->callback = func;
        newjob->timer = NULL;
        newjob->running = false;
        newjob->immediatly_running = false;

        std::pair<std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator, bool> result
        = jobs_.insert(make_pair(name, newjob));
        if (!result.second)
        {
            return false;
        }
        boost::shared_ptr<ScheduleOP> job = result.first->second;

        uint32_t delay = job->delay_start;
        job->timer = new QueueTimer(&timerCallback, job.get(), delay,
                                    job->default_interval);
        if (job->timer == NULL)
        {
            return false;
        }
        const bool started =  job->timer->start();
        if (started)
        {
            return true;
        }
        else
        {
            delete job->timer;
            job->timer = NULL;
            return false;
        }
    }

    bool runJobImmediatly(const std::string& name, int calltype, bool sync)
    {
        boost::mutex::scoped_lock l(mutex_);
        std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.find(name);
        if (itr == jobs_.end())
        {
            std::cout << "schedule job not found:" << name << std::endl;
            return false;
        }
        boost::shared_ptr<ScheduleOP> job = itr->second;
        if (job && job->timer)
        {
            int retry = 5;
            while (job->running || job->immediatly_running)
            {
                if (retry-- < 0)
                {
                    std::cout << "schedule job already running:" << name << std::endl;
                    return false;
                }
                sleep(1);
            }
            {
                boost::mutex::scoped_lock job_guard(job->jobmutex);
                if (job->running || job->immediatly_running)
                    return false;
                job->immediatly_running = true;
            }
            mutex_.unlock();
            try{
                boost::scoped_ptr<boost::thread> run_thread;
                run_thread.reset(new boost::thread(boost::bind(job->callback, calltype)));
                run_thread->join();
            } catch(const std::exception& e) {
                std::cout << "run job exception: " << e.what() << std::endl;
                mutex_.lock();
                {
                    boost::mutex::scoped_lock job_guard(job->jobmutex);
                    job->immediatly_running = false;
                }
                cond_.notify_all();
                throw e;
            }
            mutex_.lock();
            {
                boost::mutex::scoped_lock job_guard(job->jobmutex);
                job->immediatly_running = false;
            }
            cond_.notify_all();
            return true;
        }
        std::cout << "schedule job timer null:" << name << std::endl;
        return false;
    }

    bool removeJob(const std::string &name)
    {
        boost::mutex::scoped_lock l(mutex_);
        std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.find(name);
        if (itr == jobs_.end())
        {
            return false;
        }
        else
        {
            boost::shared_ptr<ScheduleOP> job = itr->second;
            if (job->timer != NULL)
            {
                job->timer->stop();
                delete job->timer;
                job->timer = NULL;
            }
            while (job->immediatly_running)
                cond_.wait(l);
            jobs_.erase(itr);
            return true;
        }
    }

private:
    static void timerCallback(void *param)
    {
        ScheduleOP *job = reinterpret_cast<ScheduleOP *>(param);

        {
            boost::mutex::scoped_lock job_guard(job->jobmutex);
            if (job->running || job->immediatly_running)
                return;
            job->running = true;
        }

        job->callback(0);

        {
            boost::mutex::scoped_lock job_guard(job->jobmutex);
            job->running = false;
        }
    }

    std::map<std::string, boost::shared_ptr<ScheduleOP> > jobs_;
    boost::condition_variable cond_;
    boost::mutex mutex_;
};

bool Scheduler::addJob(const string &name, uint32_t default_interval,
                       uint32_t delay_start, const boost::function<void (int)>& func)
{
    return Singleton<SchedulerImpl>::get()->addJob(name, default_interval, delay_start, func);
}

bool Scheduler::removeJob(const string &name)
{
    return Singleton<SchedulerImpl>::get()->removeJob(name);
}

void Scheduler::removeAllJobs()
{
    Singleton<SchedulerImpl>::get()->removeAllJobs();
}

bool Scheduler::runJobImmediatly(const std::string& name, int calltype, bool sync)
{
    return Singleton<SchedulerImpl>::get()->runJobImmediatly(name, calltype, sync);
}

}
}
<commit_msg>fix scheduler<commit_after>#include <util/singleton.h>
#include <util/scheduler.h>
#include <util/timer.h>
#include <iostream>

#include <map>
#include <boost/thread.hpp>

using namespace std;

namespace izenelib{
namespace util{

class QueueTimer : public Timer
{
public:
    QueueTimer(void (*callback)(void *),
               void *arg,
               uint32_t due_time,
               uint32_t period)
            :callback_(callback),
             arg_(arg),
             due_time_(due_time),
             period_(period)
    {}

    bool start()
    {
        return Timer::start(due_time_, period_);
    }

    bool startNow()
    {
        return Timer::start(0, period_);
    }

    virtual void signaled()
    {
        callback_(arg_);
    }

private:
    void (*callback_)(void *);
    void *arg_;
    uint32_t due_time_;
    uint32_t period_;
};

struct ScheduleOP
{
    std::string name;
    uint32_t default_interval;
    uint32_t delay_start;
    boost::function<void (int)> callback;
    QueueTimer* timer;
    volatile bool running;
    volatile bool immediatly_running;
    boost::mutex jobmutex;
};

class SchedulerImpl
{
public:
    SchedulerImpl() {}

    virtual ~SchedulerImpl()
    {
        removeAllJobs();
    }

    void removeAllJobs()
    {
        boost::mutex::scoped_lock l(mutex_);
        for (std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.begin();
                itr != jobs_.end(); ++itr)
        {
            boost::shared_ptr<ScheduleOP> job = itr->second;
            if (job->timer)
            {
                job->timer->stop();
                delete job->timer;
                job->timer = NULL;
            }
        }
        jobs_.clear();
    }

    bool addJob(const string &name, uint32_t default_interval,
                uint32_t delay_start, const boost::function<void (int)>& func)
    {
        boost::mutex::scoped_lock l(mutex_);
        std::map<string, boost::shared_ptr<ScheduleOP> >::iterator find_itr = jobs_.find(name);
        if (find_itr != jobs_.end())
            return false;

        boost::shared_ptr<ScheduleOP> newjob(new ScheduleOP());
        newjob->name = name;
        newjob->default_interval = default_interval;
        newjob->delay_start = delay_start;
        newjob->callback = func;
        newjob->timer = NULL;
        newjob->running = false;
        newjob->immediatly_running = false;

        std::pair<std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator, bool> result
        = jobs_.insert(make_pair(name, newjob));
        if (!result.second)
        {
            return false;
        }
        boost::shared_ptr<ScheduleOP> job = result.first->second;

        uint32_t delay = job->delay_start;
        job->timer = new QueueTimer(&timerCallback, job.get(), delay,
                                    job->default_interval);
        if (job->timer == NULL)
        {
            return false;
        }
        const bool started =  job->timer->start();
        if (started)
        {
            return true;
        }
        else
        {
            delete job->timer;
            job->timer = NULL;
            return false;
        }
    }

    bool runJobImmediatly(const std::string& name, int calltype, bool sync)
    {
        boost::shared_ptr<ScheduleOP> job;
        {
            boost::mutex::scoped_lock l(mutex_);
            std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.find(name);
            if (itr == jobs_.end())
            {
                std::cout << "schedule job not found:" << name << std::endl;
                return false;
            }
            job = itr->second;
        }
        if (job)
        {
            int retry = 5;
            while (job->running || job->immediatly_running)
            {
                if (retry-- < 0)
                {
                    std::cout << "schedule job already running:" << name << std::endl;
                    return false;
                }
                sleep(1);
            }
            {
                boost::mutex::scoped_lock job_guard(job->jobmutex);
                if (job->running || job->immediatly_running)
                    return false;
                job->immediatly_running = true;
            }
            try{
                boost::scoped_ptr<boost::thread> run_thread;
                run_thread.reset(new boost::thread(boost::bind(job->callback, calltype)));
                run_thread->join();
            } catch(const std::exception& e) {
                std::cout << "run job exception: " << e.what() << std::endl;
                {
                    boost::mutex::scoped_lock job_guard(job->jobmutex);
                    job->immediatly_running = false;
                }
                throw e;
            }
            {
                boost::mutex::scoped_lock job_guard(job->jobmutex);
                job->immediatly_running = false;
            }
            return true;
        }
        std::cout << "schedule job null:" << name << std::endl;
        return false;
    }

    bool removeJob(const std::string &name)
    {
        boost::mutex::scoped_lock l(mutex_);
        std::map<std::string, boost::shared_ptr<ScheduleOP> >::iterator itr = jobs_.find(name);
        if (itr == jobs_.end())
        {
            return false;
        }
        else
        {
            boost::shared_ptr<ScheduleOP> job = itr->second;
            if (job->timer != NULL)
            {
                job->timer->stop();
                delete job->timer;
                job->timer = NULL;
            }
            jobs_.erase(itr);
            return true;
        }
    }

private:
    static void timerCallback(void *param)
    {
        ScheduleOP *job = reinterpret_cast<ScheduleOP *>(param);

        {
            boost::mutex::scoped_lock job_guard(job->jobmutex);
            if (job->running || job->immediatly_running)
                return;
            job->running = true;
        }

        job->callback(0);

        {
            boost::mutex::scoped_lock job_guard(job->jobmutex);
            job->running = false;
        }
    }

    std::map<std::string, boost::shared_ptr<ScheduleOP> > jobs_;
    boost::condition_variable cond_;
    boost::mutex mutex_;
};

bool Scheduler::addJob(const string &name, uint32_t default_interval,
                       uint32_t delay_start, const boost::function<void (int)>& func)
{
    return Singleton<SchedulerImpl>::get()->addJob(name, default_interval, delay_start, func);
}

bool Scheduler::removeJob(const string &name)
{
    return Singleton<SchedulerImpl>::get()->removeJob(name);
}

void Scheduler::removeAllJobs()
{
    Singleton<SchedulerImpl>::get()->removeAllJobs();
}

bool Scheduler::runJobImmediatly(const std::string& name, int calltype, bool sync)
{
    return Singleton<SchedulerImpl>::get()->runJobImmediatly(name, calltype, sync);
}

}
}
<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * 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 "DeviceKey.h"

#if DEVICEKEY_ENABLED
#include "mbedtls/config.h"
#include "mbedtls/cmac.h"
#include "mbedtls/platform.h"
#include "features/storage/kvstore/include/KVStore.h"
#include "features/storage/kvstore/tdbstore/TDBStore.h"
#include "features/storage/kvstore/kv_map/KVMap.h"
#include "features/storage/kvstore/conf/kv_config.h"
#include "mbed_wait_api.h"
#include <stdlib.h>
#include "platform/mbed_error.h"
#include <string.h>
#include "entropy.h"
#include "mbed_trace.h"

#define TRACE_GROUP "DEVKEY"

#if !defined(MBEDTLS_CMAC_C)
#error [NOT_SUPPORTED] MBEDTLS_CMAC_C needs to be enabled for this driver
#else

namespace mbed {

#define DEVKEY_WRITE_UINT32_LE( dst, src )                              \
    do                                                                  \
    {                                                                   \
        (dst)[0] = ( (src) >> 0 ) & 0xFF;                               \
        (dst)[1] = ( (src) >> 8 ) & 0xFF;                               \
        (dst)[2] = ( (src) >> 16 ) & 0xFF;                              \
        (dst)[3] = ( (src) >> 24 ) & 0xFF;                              \
    } while( 0 )

#define DEVKEY_WRITE_UINT8_LE( dst, src )                               \
    do                                                                  \
    {                                                                   \
        (dst)[0] = (src) & 0xFF;                                        \
    } while( 0 )

DeviceKey::DeviceKey()
{

    int ret = kv_init_storage_config();
    if (ret != MBED_SUCCESS) {
        tr_error("DeviceKey: Fail to initialize KvStore configuration.");
    }
#if defined(MBEDTLS_PLATFORM_C)
    ret = mbedtls_platform_setup(NULL);
    if (ret != MBED_SUCCESS) {
        tr_error("DeviceKey: Fail in mbedtls_platform_setup.");
    }
#endif /* MBEDTLS_PLATFORM_C */
    return;
}

DeviceKey::~DeviceKey()
{
#if defined(MBEDTLS_PLATFORM_C)
    mbedtls_platform_teardown(NULL);
#endif /* MBEDTLS_PLATFORM_C */
    return;
}

int DeviceKey::generate_derived_key(const unsigned char *salt, size_t isalt_size, unsigned char *output,
                                    uint16_t ikey_type)
{
    uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
    size_t actual_size = DEVICE_KEY_32BYTE;

    if (DEVICE_KEY_16BYTE != ikey_type && DEVICE_KEY_32BYTE != ikey_type) {
        return DEVICEKEY_INVALID_KEY_TYPE;
    }

    actual_size = DEVICE_KEY_16BYTE != ikey_type ? DEVICE_KEY_32BYTE : DEVICE_KEY_16BYTE;

    //First try to read the key from KVStore
    int ret = read_key_from_kvstore(key_buff, actual_size);
    if (DEVICEKEY_SUCCESS != ret) {
        return ret;
    }

    ret = get_derived_key(key_buff, actual_size, salt, isalt_size, output, ikey_type);
    return ret;
}

int DeviceKey::device_inject_root_of_trust(uint32_t *value, size_t isize)
{
    return write_key_to_kvstore(value, isize);
}

int DeviceKey::write_key_to_kvstore(uint32_t *input, size_t isize)
{
    if (DEVICE_KEY_16BYTE != isize && DEVICE_KEY_32BYTE != isize) {
        return DEVICEKEY_INVALID_KEY_SIZE;
    }

    //First we read if key exist. If it is exists, we return DEVICEKEY_ALREADY_EXIST error
    uint32_t read_key[DEVICE_KEY_32BYTE / sizeof(uint32_t)] = {0};
    size_t read_size = DEVICE_KEY_32BYTE;
    int ret = read_key_from_kvstore(read_key, read_size);
    if (DEVICEKEY_SUCCESS == ret) {
        return DEVICEKEY_ALREADY_EXIST;
    }
    if (DEVICEKEY_NOT_FOUND != ret) {
        return ret;
    }

    KVMap &kv_map = KVMap::get_instance();
    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
    if (inner_store == NULL) {
        return DEVICEKEY_SAVE_FAILED;
    }

    ret = ((TDBStore *)inner_store)->reserved_data_set(input, isize);
    if (MBED_ERROR_WRITE_FAILED == ret) {
        return DEVICEKEY_SAVE_FAILED;
    }

    if (MBED_SUCCESS != ret) {
        return DEVICEKEY_KVSTORE_UNPREDICTED_ERROR;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::read_key_from_kvstore(uint32_t *output, size_t &size)
{
    if (size > (uint16_t) -1) {
        return DEVICEKEY_INVALID_PARAM;
    }

    KVMap &kv_map = KVMap::get_instance();
    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
    if (inner_store == NULL) {
        return DEVICEKEY_NOT_FOUND;
    }

    int kvStatus = ((TDBStore *)inner_store)->reserved_data_get(output, size, &size);
    if (MBED_ERROR_ITEM_NOT_FOUND == kvStatus) {
        return DEVICEKEY_NOT_FOUND;
    }

    if (MBED_ERROR_READ_FAILED == kvStatus || MBED_ERROR_INVALID_SIZE == kvStatus) {
        return DEVICEKEY_READ_FAILED;
    }

    if (MBED_SUCCESS != kvStatus) {
        return DEVICEKEY_KVSTORE_UNPREDICTED_ERROR;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::get_derived_key(uint32_t *ikey_buff, size_t ikey_size, const unsigned char *isalt,
                               size_t isalt_size, unsigned char *output, uint32_t ikey_type)
{
    //KDF in counter mode implementation as described in Section 5.1
    //of NIST SP 800-108, Recommendation for Key Derivation Using Pseudorandom Functions
    int ret;
    size_t counter = 0;
    char separator = 0x00;
    mbedtls_cipher_context_t ctx;
    unsigned char output_len_enc[ 4 ] = {0};
    unsigned char counter_enc[ 1 ] = {0};

    DEVKEY_WRITE_UINT32_LE(output_len_enc, ikey_type);

    mbedtls_cipher_type_t mbedtls_cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
    if (DEVICE_KEY_32BYTE == ikey_size) {
        mbedtls_cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
    }

    const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(mbedtls_cipher_type);

    do {

        mbedtls_cipher_init(&ctx);
        ret = mbedtls_cipher_setup(&ctx, cipher_info);
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_starts(&ctx, (unsigned char *)ikey_buff, ikey_size * 8);
        if (ret != 0) {
            goto finish;
        }

        DEVKEY_WRITE_UINT8_LE(counter_enc, (counter + 1));

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)counter_enc, sizeof(counter_enc));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, isalt, isalt_size);
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&separator, sizeof(char));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&output_len_enc, sizeof(output_len_enc));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_finish(&ctx, output + (DEVICE_KEY_16BYTE * (counter)));
        if (ret != 0) {
            goto finish;
        }

        mbedtls_cipher_free(&ctx);

        counter++;

    } while (DEVICE_KEY_16BYTE * counter < ikey_type);

finish:
    if (DEVICEKEY_SUCCESS != ret) {
        mbedtls_cipher_free(&ctx);
        return DEVICEKEY_ERR_CMAC_GENERIC_FAILURE;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::generate_root_of_trust()
{
    int ret = DEVICEKEY_GENERATE_RANDOM_ERROR;
    uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
    size_t actual_size = DEVICE_KEY_32BYTE;

    if (read_key_from_kvstore(key_buff, actual_size) == DEVICEKEY_SUCCESS) {
        return DEVICEKEY_ALREADY_EXIST;
    }

#if defined(DEVICE_TRNG) || defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
    mbedtls_entropy_context *entropy = new mbedtls_entropy_context;
    mbedtls_entropy_init(entropy);
    memset(key_buff, 0, actual_size);

    ret = mbedtls_entropy_func(entropy, (unsigned char *)key_buff, actual_size);
    if (ret != MBED_SUCCESS) {
        ret = DEVICEKEY_GENERATE_RANDOM_ERROR;
    } else {
        ret = DEVICEKEY_SUCCESS;
    }

    mbedtls_entropy_free(entropy);
    delete entropy;

    if (ret == MBED_SUCCESS) {
        ret = device_inject_root_of_trust(key_buff, actual_size);
    }
#endif

    return ret;
}

} // namespace mbed

#endif
#endif

<commit_msg>Use correct return value.<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * 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 "DeviceKey.h"

#if DEVICEKEY_ENABLED
#include "mbedtls/config.h"
#include "mbedtls/cmac.h"
#include "mbedtls/platform.h"
#include "features/storage/kvstore/include/KVStore.h"
#include "features/storage/kvstore/tdbstore/TDBStore.h"
#include "features/storage/kvstore/kv_map/KVMap.h"
#include "features/storage/kvstore/conf/kv_config.h"
#include "mbed_wait_api.h"
#include <stdlib.h>
#include "platform/mbed_error.h"
#include <string.h>
#include "entropy.h"
#include "mbed_trace.h"

#define TRACE_GROUP "DEVKEY"

#if !defined(MBEDTLS_CMAC_C)
#error [NOT_SUPPORTED] MBEDTLS_CMAC_C needs to be enabled for this driver
#else

namespace mbed {

#define DEVKEY_WRITE_UINT32_LE( dst, src )                              \
    do                                                                  \
    {                                                                   \
        (dst)[0] = ( (src) >> 0 ) & 0xFF;                               \
        (dst)[1] = ( (src) >> 8 ) & 0xFF;                               \
        (dst)[2] = ( (src) >> 16 ) & 0xFF;                              \
        (dst)[3] = ( (src) >> 24 ) & 0xFF;                              \
    } while( 0 )

#define DEVKEY_WRITE_UINT8_LE( dst, src )                               \
    do                                                                  \
    {                                                                   \
        (dst)[0] = (src) & 0xFF;                                        \
    } while( 0 )

DeviceKey::DeviceKey()
{

    int ret = kv_init_storage_config();
    if (ret != MBED_SUCCESS) {
        tr_error("DeviceKey: Fail to initialize KvStore configuration.");
    }
#if defined(MBEDTLS_PLATFORM_C)
    ret = mbedtls_platform_setup(NULL);
    if (ret != MBED_SUCCESS) {
        tr_error("DeviceKey: Fail in mbedtls_platform_setup.");
    }
#endif /* MBEDTLS_PLATFORM_C */
    return;
}

DeviceKey::~DeviceKey()
{
#if defined(MBEDTLS_PLATFORM_C)
    mbedtls_platform_teardown(NULL);
#endif /* MBEDTLS_PLATFORM_C */
    return;
}

int DeviceKey::generate_derived_key(const unsigned char *salt, size_t isalt_size, unsigned char *output,
                                    uint16_t ikey_type)
{
    uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
    size_t actual_size = DEVICE_KEY_32BYTE;

    if (DEVICE_KEY_16BYTE != ikey_type && DEVICE_KEY_32BYTE != ikey_type) {
        return DEVICEKEY_INVALID_KEY_TYPE;
    }

    actual_size = DEVICE_KEY_16BYTE != ikey_type ? DEVICE_KEY_32BYTE : DEVICE_KEY_16BYTE;

    //First try to read the key from KVStore
    int ret = read_key_from_kvstore(key_buff, actual_size);
    if (DEVICEKEY_SUCCESS != ret) {
        return ret;
    }

    ret = get_derived_key(key_buff, actual_size, salt, isalt_size, output, ikey_type);
    return ret;
}

int DeviceKey::device_inject_root_of_trust(uint32_t *value, size_t isize)
{
    return write_key_to_kvstore(value, isize);
}

int DeviceKey::write_key_to_kvstore(uint32_t *input, size_t isize)
{
    if (DEVICE_KEY_16BYTE != isize && DEVICE_KEY_32BYTE != isize) {
        return DEVICEKEY_INVALID_KEY_SIZE;
    }

    //First we read if key exist. If it is exists, we return DEVICEKEY_ALREADY_EXIST error
    uint32_t read_key[DEVICE_KEY_32BYTE / sizeof(uint32_t)] = {0};
    size_t read_size = DEVICE_KEY_32BYTE;
    int ret = read_key_from_kvstore(read_key, read_size);
    if (DEVICEKEY_SUCCESS == ret) {
        return DEVICEKEY_ALREADY_EXIST;
    }
    if (DEVICEKEY_NOT_FOUND != ret) {
        return ret;
    }

    KVMap &kv_map = KVMap::get_instance();
    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
    if (inner_store == NULL) {
        return DEVICEKEY_SAVE_FAILED;
    }

    ret = ((TDBStore *)inner_store)->reserved_data_set(input, isize);
    if (MBED_ERROR_WRITE_FAILED == ret) {
        return DEVICEKEY_SAVE_FAILED;
    }

    if (MBED_SUCCESS != ret) {
        return DEVICEKEY_KVSTORE_UNPREDICTED_ERROR;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::read_key_from_kvstore(uint32_t *output, size_t &size)
{
    if (size > (uint16_t) -1) {
        return DEVICEKEY_INVALID_PARAM;
    }

    KVMap &kv_map = KVMap::get_instance();
    KVStore *inner_store = kv_map.get_internal_kv_instance(NULL);
    if (inner_store == NULL) {
        return DEVICEKEY_NOT_FOUND;
    }

    int kvStatus = ((TDBStore *)inner_store)->reserved_data_get(output, size, &size);
    if (MBED_ERROR_ITEM_NOT_FOUND == kvStatus) {
        return DEVICEKEY_NOT_FOUND;
    }

    if (MBED_ERROR_READ_FAILED == kvStatus || MBED_ERROR_INVALID_SIZE == kvStatus) {
        return DEVICEKEY_READ_FAILED;
    }

    if (MBED_SUCCESS != kvStatus) {
        return DEVICEKEY_KVSTORE_UNPREDICTED_ERROR;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::get_derived_key(uint32_t *ikey_buff, size_t ikey_size, const unsigned char *isalt,
                               size_t isalt_size, unsigned char *output, uint32_t ikey_type)
{
    //KDF in counter mode implementation as described in Section 5.1
    //of NIST SP 800-108, Recommendation for Key Derivation Using Pseudorandom Functions
    int ret;
    size_t counter = 0;
    char separator = 0x00;
    mbedtls_cipher_context_t ctx;
    unsigned char output_len_enc[ 4 ] = {0};
    unsigned char counter_enc[ 1 ] = {0};

    DEVKEY_WRITE_UINT32_LE(output_len_enc, ikey_type);

    mbedtls_cipher_type_t mbedtls_cipher_type = MBEDTLS_CIPHER_AES_128_ECB;
    if (DEVICE_KEY_32BYTE == ikey_size) {
        mbedtls_cipher_type = MBEDTLS_CIPHER_AES_256_ECB;
    }

    const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(mbedtls_cipher_type);

    do {

        mbedtls_cipher_init(&ctx);
        ret = mbedtls_cipher_setup(&ctx, cipher_info);
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_starts(&ctx, (unsigned char *)ikey_buff, ikey_size * 8);
        if (ret != 0) {
            goto finish;
        }

        DEVKEY_WRITE_UINT8_LE(counter_enc, (counter + 1));

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)counter_enc, sizeof(counter_enc));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, isalt, isalt_size);
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&separator, sizeof(char));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_update(&ctx, (unsigned char *)&output_len_enc, sizeof(output_len_enc));
        if (ret != 0) {
            goto finish;
        }

        ret = mbedtls_cipher_cmac_finish(&ctx, output + (DEVICE_KEY_16BYTE * (counter)));
        if (ret != 0) {
            goto finish;
        }

        mbedtls_cipher_free(&ctx);

        counter++;

    } while (DEVICE_KEY_16BYTE * counter < ikey_type);

finish:
    if (DEVICEKEY_SUCCESS != ret) {
        mbedtls_cipher_free(&ctx);
        return DEVICEKEY_ERR_CMAC_GENERIC_FAILURE;
    }

    return DEVICEKEY_SUCCESS;
}

int DeviceKey::generate_root_of_trust()
{
    int ret = DEVICEKEY_GENERATE_RANDOM_ERROR;
    uint32_t key_buff[DEVICE_KEY_32BYTE / sizeof(uint32_t)];
    size_t actual_size = DEVICE_KEY_32BYTE;

    if (read_key_from_kvstore(key_buff, actual_size) == DEVICEKEY_SUCCESS) {
        return DEVICEKEY_ALREADY_EXIST;
    }

#if defined(DEVICE_TRNG) || defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
    mbedtls_entropy_context *entropy = new mbedtls_entropy_context;
    mbedtls_entropy_init(entropy);
    memset(key_buff, 0, actual_size);

    ret = mbedtls_entropy_func(entropy, (unsigned char *)key_buff, actual_size);
    if (ret != MBED_SUCCESS) {
        ret = DEVICEKEY_GENERATE_RANDOM_ERROR;
    } else {
        ret = DEVICEKEY_SUCCESS;
    }

    mbedtls_entropy_free(entropy);
    delete entropy;

    if (ret == DEVICEKEY_SUCCESS) {
        ret = device_inject_root_of_trust(key_buff, actual_size);
    }
#endif

    return ret;
}

} // namespace mbed

#endif
#endif

<|endoftext|>