<commit_before>/*
 * Copyright (C) 2009-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.
 */

#include <libport/cstdio>
#include <libport/debug.hh>
#include <libport/format.hh>
#include <libport/iostream>
#include <libport/path.hxx>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>
#include <libport/xltdl.hh>

GD_CATEGORY(Libport.Xltdl);

extern "C"
{
  int
  libport_xlt_details_identity(int i)
  {
    return i;
  }
}

namespace libport
{
  namespace xlt
  {
    namespace details
    {

       /// \param verbosity  the current debug level.
       /// \param level      the level of this message.
       static
       int
       ltdebug(unsigned /* verbosity */,
               unsigned level, const char* format, va_list args)
       {
         int errors = 0;
         char* msg = 0;
         errors += vasprintf(&msg, format, args) < 0;
         if (!errors && msg)
         {
           LIBPORT_USE(level);
           GD_FINFO_DEBUG("%s%s", std::string(level * 2, ' '), msg);
           free(msg);
         }
         return errors;
       }

       void init()
       {
         static bool first = true;
         if (first)
         {
           first = false;
         }
       }
     }
   }

   /*------------------------.
   | xlt_advise::exception.  |
   `------------------------*/

   xlt_advise::exception::exception(const std::string& msg)
     : std::runtime_error(msg)
   {}

   /*-------------.
   | xlt_advise.  |
   `-------------*/

   xlt_advise::xlt_advise()
     throw(xlt_advise::exception)
     : path_()
   {
     global_ = true;
     xlt::details::init();
  }

  // FIXME: Bad: dtors must not throw.
  xlt_advise::~xlt_advise()
    throw(xlt_advise::exception)
  {
    // FIXME: lt_dlexit when we refcount.
  }

  xlt_advise&
  xlt_advise::global(bool global)
    throw(xlt_advise::exception)
  {
    this->global_ = global;
    return *this;
  }

  xlt_advise&
  xlt_advise::ext()
    throw(xlt_advise::exception)
  {
    return *this;
  }

  const file_library&
  xlt_advise::path() const throw()
  {
    return path_;
  }

  file_library&
  xlt_advise::path() throw()
  {
    return path_;
  }

  xlt_advise&
  xlt_advise::path(const file_library& p) throw()
  {
    path_ = p;
    return *this;
  }

  lt_dlhandle
  xlt_advise::dlopen_(const std::string& s) const
    throw(xlt_advise::exception)
  {
    lt_dlhandle res = dlopen(s.c_str(), global_?RTLD_GLOBAL:RTLD_LOCAL);
    GD_FINFO_TRACE("loading %s: %s", s, res ? "pass" : "fail");
    return res;
  }

#if defined WIN32
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Windows
#elif defined __APPLE__
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Apple
#else
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Linux
#endif

  xlt_handle
  xlt_advise::open(const std::string& ss)
    throw(xlt_advise::exception)
  {
    std::string s(ss);
    GD_FINFO_TRACE("loading %s", s);

    // Clear the error flags from previous runs.
    //
    // FIXME: This should be done in libltdl itself.  The problem
    // probably arose from our patches to preserve the first error
    // when traversing the user path: now, even on success, the error
    // flag remains set, and the following run is hindered by it.  We
    // need to complete this patch with a means to ensure that the
    // error flags is restored to its previous state (typically
    // no-error) when eventually we managed to load the file.

    lt_dlhandle res = 0;
    const char* libext = APPLE_LINUX_WINDOWS(".dylib", ".so", ".dll");
    if (s.substr(s.length() - strlen(libext)) != libext)
      s += libext;
    // We cannot simply use search_file in file_library, because we
    // don't know the extension of the file we are looking for (*.la,
    // *.so, *.dyld etc.).  That's an implementation detail that ltdl
    // saves us from.
    if (path_.search_path_get().empty() || libport::path(s).absolute_get())
    {
      std::cerr <<"try " << s << std::endl;
      res = dlopen_(s);
    }
    else
      foreach (const libport::path& p, path_.search_path_get())
      {
        std::cerr << "try " << p << " " << s << std::endl;
        if ((res = dlopen_(p / s)))
          break;
      }
    if (!res)
      fail(libport::format("failed to open %s", s));

    return res;
  }

  /// Throw an exception, or exit with exit_failure_ if nonnull.
  ATTRIBUTE_NORETURN
  void
  xlt_advise::fail(std::string msg)
    throw(xlt_advise::exception)
  {
    perror("fail");
    msg += ": ";
    const char* dle = dlerror();
    if (dle)
      msg += dle;
    throw exception(msg);
  }

  /*-------------.
  | xlt_handle.  |
  `-------------*/

  xlt_handle::xlt_handle(lt_dlhandle h)
    : handle(h)
  {}

  xlt_handle::~xlt_handle()
  {
    // FIXME: We can't close -- yet.  We need to keep track of the
    // number of trackers.  Otherwise a simple "handle h =
    // advise.open" will close the handle when cleaning the temporary
    // made by "advise.open".

    // close();
  }

  void
  xlt_handle::close()
    throw(xlt_handle::exception)
  {
    if (handle)
    {
      int errors = dlclose(handle);
      handle = 0;
      if (errors)
        fail("cannot close");
    }
  }

  void
  xlt_handle::detach()
  {
    aver(handle);
    handle = 0;
  }

  void
  xlt_handle::attach(lt_dlhandle h)
  {
    aver(!handle);
    handle = h;
  }

  /// Throw an exception, or exit with exit_failure_ if nonnull.
  ATTRIBUTE_NORETURN
  void
  xlt_handle::fail(const std::string& msg)
    throw(xlt_advise::exception)
  {
    xlt_advise::fail(msg);
  }

  /*-------------.
  | Standalone.  |
  `-------------*/

  xlt_handle
  xlt_openext(const std::string& s, bool global, int exit_failure)
    throw (xlt_advise::exception)
  {
    try
    {
      return xlt_advise().global(global).ext().open(s);
    }
    catch (std::exception& s)
    {
      std::cerr << libport::program_name()
                << ": "
                << s.what()
                << std::endl
                << libport::exit(exit_failure);
    }
  }
}
<commit_msg>dlopen: Add missing mandatory flag.<commit_after>/*
 * Copyright (C) 2009-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.
 */

#include <libport/cstdio>
#include <libport/debug.hh>
#include <libport/format.hh>
#include <libport/iostream>
#include <libport/path.hxx>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>
#include <libport/xltdl.hh>

GD_CATEGORY(Libport.Xltdl);

extern "C"
{
  int
  libport_xlt_details_identity(int i)
  {
    return i;
  }
}

namespace libport
{
  namespace xlt
  {
    namespace details
    {

       /// \param verbosity  the current debug level.
       /// \param level      the level of this message.
       static
       int
       ltdebug(unsigned /* verbosity */,
               unsigned level, const char* format, va_list args)
       {
         int errors = 0;
         char* msg = 0;
         errors += vasprintf(&msg, format, args) < 0;
         if (!errors && msg)
         {
           LIBPORT_USE(level);
           GD_FINFO_DEBUG("%s%s", std::string(level * 2, ' '), msg);
           free(msg);
         }
         return errors;
       }

       void init()
       {
         static bool first = true;
         if (first)
         {
           first = false;
         }
       }
     }
   }

   /*------------------------.
   | xlt_advise::exception.  |
   `------------------------*/

   xlt_advise::exception::exception(const std::string& msg)
     : std::runtime_error(msg)
   {}

   /*-------------.
   | xlt_advise.  |
   `-------------*/

   xlt_advise::xlt_advise()
     throw(xlt_advise::exception)
     : path_()
   {
     global_ = true;
     xlt::details::init();
  }

  // FIXME: Bad: dtors must not throw.
  xlt_advise::~xlt_advise()
    throw(xlt_advise::exception)
  {
    // FIXME: lt_dlexit when we refcount.
  }

  xlt_advise&
  xlt_advise::global(bool global)
    throw(xlt_advise::exception)
  {
    this->global_ = global;
    return *this;
  }

  xlt_advise&
  xlt_advise::ext()
    throw(xlt_advise::exception)
  {
    return *this;
  }

  const file_library&
  xlt_advise::path() const throw()
  {
    return path_;
  }

  file_library&
  xlt_advise::path() throw()
  {
    return path_;
  }

  xlt_advise&
  xlt_advise::path(const file_library& p) throw()
  {
    path_ = p;
    return *this;
  }

  lt_dlhandle
  xlt_advise::dlopen_(const std::string& s) const
    throw(xlt_advise::exception)
  {
    lt_dlhandle res = dlopen(s.c_str(), RTLD_LAZY | (global_?RTLD_GLOBAL:RTLD_LOCAL));
    GD_FINFO_TRACE("loading %s: %s", s, res ? "pass" : "fail");
    return res;
  }

#if defined WIN32
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Windows
#elif defined __APPLE__
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Apple
#else
# define APPLE_LINUX_WINDOWS(Apple, Linux, Windows) Linux
#endif

  xlt_handle
  xlt_advise::open(const std::string& ss)
    throw(xlt_advise::exception)
  {
    std::string s(ss);
    GD_FINFO_TRACE("loading %s", s);

    // Clear the error flags from previous runs.
    //
    // FIXME: This should be done in libltdl itself.  The problem
    // probably arose from our patches to preserve the first error
    // when traversing the user path: now, even on success, the error
    // flag remains set, and the following run is hindered by it.  We
    // need to complete this patch with a means to ensure that the
    // error flags is restored to its previous state (typically
    // no-error) when eventually we managed to load the file.

    lt_dlhandle res = 0;
    const char* libext = APPLE_LINUX_WINDOWS(".dylib", ".so", ".dll");
    if (s.substr(s.length() - strlen(libext)) != libext)
      s += libext;
    // We cannot simply use search_file in file_library, because we
    // don't know the extension of the file we are looking for (*.la,
    // *.so, *.dyld etc.).  That's an implementation detail that ltdl
    // saves us from.
    if (path_.search_path_get().empty() || libport::path(s).absolute_get())
    {
      std::cerr <<"try " << s << std::endl;
      res = dlopen_(s);
    }
    else
      foreach (const libport::path& p, path_.search_path_get())
      {
        std::cerr << "try " << p << " " << s << std::endl;
        if ((res = dlopen_(p / s)))
          break;
      }
    if (!res)
      fail(libport::format("failed to open %s", s));

    return res;
  }

  /// Throw an exception, or exit with exit_failure_ if nonnull.
  ATTRIBUTE_NORETURN
  void
  xlt_advise::fail(std::string msg)
    throw(xlt_advise::exception)
  {
    perror("fail");
    msg += ": ";
    const char* dle = dlerror();
    if (dle)
      msg += dle;
    throw exception(msg);
  }

  /*-------------.
  | xlt_handle.  |
  `-------------*/

  xlt_handle::xlt_handle(lt_dlhandle h)
    : handle(h)
  {}

  xlt_handle::~xlt_handle()
  {
    // FIXME: We can't close -- yet.  We need to keep track of the
    // number of trackers.  Otherwise a simple "handle h =
    // advise.open" will close the handle when cleaning the temporary
    // made by "advise.open".

    // close();
  }

  void
  xlt_handle::close()
    throw(xlt_handle::exception)
  {
    if (handle)
    {
      int errors = dlclose(handle);
      handle = 0;
      if (errors)
        fail("cannot close");
    }
  }

  void
  xlt_handle::detach()
  {
    aver(handle);
    handle = 0;
  }

  void
  xlt_handle::attach(lt_dlhandle h)
  {
    aver(!handle);
    handle = h;
  }

  /// Throw an exception, or exit with exit_failure_ if nonnull.
  ATTRIBUTE_NORETURN
  void
  xlt_handle::fail(const std::string& msg)
    throw(xlt_advise::exception)
  {
    xlt_advise::fail(msg);
  }

  /*-------------.
  | Standalone.  |
  `-------------*/

  xlt_handle
  xlt_openext(const std::string& s, bool global, int exit_failure)
    throw (xlt_advise::exception)
  {
    try
    {
      return xlt_advise().global(global).ext().open(s);
    }
    catch (std::exception& s)
    {
      std::cerr << libport::program_name()
                << ": "
                << s.what()
                << std::endl
                << libport::exit(exit_failure);
    }
  }
}
<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_COMMON_H_
#define LUWRA_COMMON_H_

// Check C++ version
#if !defined(__cplusplus) || __cplusplus < 201402L
	#error You need a C++14 compliant compiler
#endif

#include <lua.hpp>

// Check for proper Lua version
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503 || LUA_VERSION_NUM >= 600
	#error Luwra has not been tested against your installed version of Lua
#endif

#define LUWRA_NS_BEGIN namespace luwra {

#define LUWRA_NS_END }

#endif
<commit_msg>Add version macros<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_COMMON_H_
#define LUWRA_COMMON_H_

// Check C++ version
#if !defined(__cplusplus) || __cplusplus < 201402L
	#error You need a C++14 compliant compiler
#endif

#include <lua.hpp>

// Check for proper Lua version
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503 || LUA_VERSION_NUM >= 600
	#error Luwra has not been tested against your installed version of Lua
#endif

// Namespaces
#define LUWRA_NS_BEGIN namespace luwra {
#define LUWRA_NS_END }

// Version MAJOR.MINOR.PATH
#define LUWRA_VERSION_MAJOR 0
#define LUWRA_VERSION_MINOR 0
#define LUWRA_VERSION_PATCH 0

#endif
<|endoftext|>


<commit_before><commit_msg>a malformed string here can force an out of bounds indexOf<commit_after><|endoftext|>


<commit_before>#include "snow_drift.h"
#include "forecast_time.h"
#include "level.h"
#include "logger.h"
#include "metutil.h"
#include "util.h"

#include "fetcher.h"
#include "hitool.h"
#include "radon.h"
#include "writer.h"

using namespace himan;
using namespace himan::plugin;

const param SDIParam("SNOWDRIFT-N");
const param SAParam("SNACC-H");
const param DAParam("SNDACC-N");
const double SFLimit = 0.09;

double DriftMagnitude(double ff, double mi);
double DriftIndex(double sv);
double MobilityIndex(double da, double sa);

void CalculateSnowDriftIndex(info_t& myTargetInfo, const std::vector<double>& T, const std::vector<double>& FF,
                             const std::vector<double>& SF, const std::vector<double>& pSA,
                             const std::vector<double>& pDA)
{
	myTargetInfo->Find<param>(SDIParam);
	auto& SI = VEC(myTargetInfo);
	myTargetInfo->Find<param>(SAParam);
	auto& SA = VEC(myTargetInfo);
	myTargetInfo->Find<param>(DAParam);
	auto& DA = VEC(myTargetInfo);

	for (auto&& tup : zip_range(SI, SA, DA, T, FF, SF, pSA, pDA))
	{
		auto& si = tup.get<0>();        // snow drift index
		auto& sa = tup.get<1>();        // accumulated snow cover age
		auto& da = tup.get<2>();        // accumulated snowdrift value
		const auto t = tup.get<3>();    // temperature
		const auto ff = tup.get<4>();   // wind speed
		const auto sf = tup.get<5>();   // snow fall rate (mm/h)
		const auto psa = tup.get<6>();  // previous accumulated snow cover age
		const auto pda = tup.get<7>();  // previous accumulated snowdrift value

		if (IsMissing(t) || IsMissing(ff) || IsMissing(sf))
		{
			continue;
		}

		if (t > 273.15)
		{
			// no possibility for snow drift until next snow fall
			si = 0;
			sa = 0;
			da = 0;
			continue;
		}

		/*
		        this is not present in the fortran code either
		        if (ff < 6.0)
		        {
		            si = 0;
		        }
		*/

		if (sf > SFLimit)
		{
			// during snow fall
			si = DriftIndex(DriftMagnitude(ff, 1.0));
			sa = 0;
			da = 0;
		}
		else
		{
			// after snow fall
			sa = psa + 1;  // add one hour to snowcover age

			if (ff < 6)
			{
				si = 0;
				da = pda;
			}
			else
			{
				const double sv = DriftMagnitude(ff, MobilityIndex(pda, sa));
				da = pda + sv;
				si = DriftIndex(sv);
			}
		}
	}
}

snow_drift::snow_drift()
{
	itsLogger = logger("snow_drift");
}

void snow_drift::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({SDIParam, SAParam, DAParam});

	itsThreadDistribution = ThreadDistribution::kThreadForForecastTypeAndLevel;

	Start();
}

void snow_drift::Calculate(std::shared_ptr<info<double>> myTargetInfo, unsigned short theThreadIndex)
{
	auto myThreadedLogger = logger("snow_driftThread #" + std::to_string(theThreadIndex));

	const auto forecastTime = myTargetInfo->Time();
	const auto forecastLevel = myTargetInfo->Level();
	const auto forecastType = myTargetInfo->ForecastType();
	const auto prod = myTargetInfo->Producer();

	if (forecastTime.Step() == 0 && prod.Id() != 107)
	{
		// We only calculate analysis hour for LAPS
		return;
	}

	if (forecastTime.StepResolution() != kHourResolution || itsConfiguration->ForecastStep() != 1)
	{
		myThreadedLogger.Error("Snow drift can only be calculated with one hour resolution");
		return;
	}

	myThreadedLogger.Info("Calculating time " + static_cast<std::string>(forecastTime.ValidDateTime()) + " level " +
	                      static_cast<std::string>(forecastLevel));

	const std::string deviceType = "CPU";

	auto TInfo = Fetch(forecastTime, level(kHeight, 2), param("T-K"), forecastType, false);
	auto FFInfo = Fetch(forecastTime, level(kHeight, 10), param("FF-MS"), forecastType, false);
	auto SFInfo = Fetch(forecastTime, level(kHeight, 0), param("SNR-KGM2"), forecastType, false);

	if (!TInfo || !FFInfo || !SFInfo)
	{
		return;
	}

	auto prevTime = forecastTime;

	std::shared_ptr<info<double>> pSAInfo, pDAInfo;

	prevTime.ValidDateTime().Adjust(kHourResolution, -1);

	// In the start of the forecast fetch the latest sa and da
	// values from LAPS producer.

	if (prod.Id() == 107 || forecastTime.Step() == 1)
	{
		prevTime.OriginDateTime(prevTime.ValidDateTime());

		// Allow up to three hours of missing data
		for (int i = 0; i < 3; i++)
		{
			pSAInfo = Fetch(prevTime, level(kHeight, 0), SAParam, forecastType, itsConfiguration->SourceGeomNames(),
			                producer(107, 0, 0, "LAPSFIN"), false);
			pDAInfo = Fetch(prevTime, level(kHeight, 0), DAParam, forecastType, itsConfiguration->SourceGeomNames(),
			                producer(107, 0, 0, "LAPSFIN"), false);

			if (pSAInfo && pDAInfo)
			{
				break;
			}

			prevTime.ValidDateTime().Adjust(kHourResolution, -1);
			prevTime.OriginDateTime(prevTime.ValidDateTime());
		}
	}
	else
	{
		pSAInfo = Fetch(prevTime, level(kHeight, 0), SAParam, forecastType, false);
		pDAInfo = Fetch(prevTime, level(kHeight, 0), DAParam, forecastType, false);
	}

	if (!pSAInfo || !pDAInfo)
	{
		if (prod.Id() != 107)
		{
			myThreadedLogger.Error("DA and SA not found from obs producer");
			return;
		}
		// If we don't have a history of sa & da, start accumulating
		// it but do not write snow index.

		std::vector<double> pSA(myTargetInfo->Grid()->Size(), 0.0);
		std::vector<double> pDA = pSA;

		myThreadedLogger.Warning("Spinup phase, producing only DA and SA");
		CalculateSnowDriftIndex(myTargetInfo, VEC(TInfo), VEC(FFInfo), VEC(SFInfo), pSA, pDA);

		myTargetInfo->Find<param>(SDIParam);
		myTargetInfo->Data().Fill(MissingDouble());
	}
	else
	{
		CalculateSnowDriftIndex(myTargetInfo, VEC(TInfo), VEC(FFInfo), VEC(SFInfo), VEC(pSAInfo), VEC(pDAInfo));
	}

	myThreadedLogger.Info("[" + deviceType + "] Missing: " + std::to_string(util::MissingPercent(*myTargetInfo)) + "%");
}

double DriftMagnitude(double ff, double mi)
{
	return (ff * ff * ff / 1728.0) * mi;
}

double DriftIndex(double sv)
{
	if (sv < 0.09)
	{
		return 0;  // no drift
	}
	else if (sv < 0.21)
	{
		return 1;  // low
	}
	else if (sv < 0.5)
	{
		return 2;  // moderate
	}
	else
	{
		return 3;  // high
	}
}

double MobilityIndex(double da, double sa)
{
	double mi = 1.0;

	if (da < 2.0 && sa < 24.0)
	{
		mi = 1.0;
	}
	else if (da >= 2.0 && da <= 6.0)
	{
		mi = 0.6;
	}
	else if (da > 6.0)
	{
		mi = 0.3;
	}

	if (sa >= 24.0 && mi == 1.0)
	{
		mi = 0.6;
	}

	return mi;
}
<commit_msg>Minor adjustments<commit_after>#include "snow_drift.h"
#include "forecast_time.h"
#include "level.h"
#include "logger.h"
#include "metutil.h"
#include "util.h"

#include "fetcher.h"
#include "hitool.h"
#include "radon.h"
#include "writer.h"

using namespace himan;
using namespace himan::plugin;

const param SDIParam("SNOWDRIFT-N");
const param SAParam("SNACC-H");
const param DAParam("SNDACC-N");
const double SFLimit = 0.09;

double DriftMagnitude(double ff, double mi);
double DriftIndex(double sv);
double MobilityIndex(double da, double sa);

void CalculateSnowDriftIndex(info_t& myTargetInfo, const std::vector<double>& T, const std::vector<double>& FF,
                             const std::vector<double>& SF, const std::vector<double>& pSA,
                             const std::vector<double>& pDA)
{
	myTargetInfo->Find<param>(SDIParam);
	auto& SI = VEC(myTargetInfo);
	myTargetInfo->Find<param>(SAParam);
	auto& SA = VEC(myTargetInfo);
	myTargetInfo->Find<param>(DAParam);
	auto& DA = VEC(myTargetInfo);

	for (auto&& tup : zip_range(SI, SA, DA, T, FF, SF, pSA, pDA))
	{
		auto& si = tup.get<0>();        // snow drift index
		auto& sa = tup.get<1>();        // accumulated snow cover age
		auto& da = tup.get<2>();        // accumulated snowdrift value
		const auto t = tup.get<3>();    // temperature
		const auto ff = tup.get<4>();   // wind speed
		const auto sf = tup.get<5>();   // snow fall rate (mm/h)
		const auto psa = tup.get<6>();  // previous accumulated snow cover age
		const auto pda = tup.get<7>();  // previous accumulated snowdrift value

		if (IsMissing(t) || IsMissing(ff) || IsMissing(sf) || IsMissing(psa) || IsMissing(pda))
		{
			continue;
		}

		if (t > 273.15)
		{
			// no possibility for snow drift until next snow fall
			si = 0;
			sa = 0;
			da = 0;
			continue;
		}

		/*
		        this is not present in the fortran code either
		        if (ff < 6.0)
		        {
		            si = 0;
		        }
		*/

		if (sf > SFLimit)
		{
			// during snow fall
			si = DriftIndex(DriftMagnitude(ff, 1.0));
			sa = 0;
			da = 0;
		}
		else
		{
			// after snow fall
			sa = psa + 1;  // add one hour to snowcover age

			if (ff < 6)
			{
				si = 0;
				da = pda;
			}
			else
			{
				const double sv = DriftMagnitude(ff, MobilityIndex(pda, sa));
				da = pda + sv;
				si = DriftIndex(sv);
			}
		}
	}
}

snow_drift::snow_drift()
{
	itsLogger = logger("snow_drift");
}

void snow_drift::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	SetParams({SDIParam, SAParam, DAParam});

	itsThreadDistribution = ThreadDistribution::kThreadForForecastTypeAndLevel;

	Start();
}

void snow_drift::Calculate(std::shared_ptr<info<double>> myTargetInfo, unsigned short theThreadIndex)
{
	auto myThreadedLogger = logger("snow_driftThread #" + std::to_string(theThreadIndex));

	const auto forecastTime = myTargetInfo->Time();
	const auto forecastLevel = myTargetInfo->Level();
	const auto forecastType = myTargetInfo->ForecastType();
	const auto prod = myTargetInfo->Producer();

	if (forecastTime.Step() == 0 && prod.Id() != 107)
	{
		// We only calculate analysis hour for LAPS
		return;
	}

	if (forecastTime.StepResolution() != kHourResolution || itsConfiguration->ForecastStep() != 1)
	{
		myThreadedLogger.Error("Snow drift can only be calculated with one hour resolution");
		return;
	}

	myThreadedLogger.Info("Calculating time " + static_cast<std::string>(forecastTime.ValidDateTime()) + " level " +
	                      static_cast<std::string>(forecastLevel));

	const std::string deviceType = "CPU";

	auto TInfo = Fetch(forecastTime, level(kHeight, 2), param("T-K"), forecastType, false);
	auto FFInfo = Fetch(forecastTime, level(kHeight, 10), param("FF-MS"), forecastType, false);
	auto SFInfo = Fetch(forecastTime, level(kHeight, 0), param("SNR-KGM2"), forecastType, false);

	if (!TInfo || !FFInfo || !SFInfo)
	{
		return;
	}

	auto prevTime = forecastTime;

	std::shared_ptr<info<double>> pSAInfo, pDAInfo;

	prevTime.ValidDateTime().Adjust(kHourResolution, -1);

	// In the start of the forecast fetch the latest sa and da
	// values from LAPS producer.

	if (prod.Id() == 107 || forecastTime.Step() == 1)
	{
		prevTime.OriginDateTime(prevTime.ValidDateTime());

		// Allow up to three hours of missing data
		for (int i = 0; i < 3; i++)
		{
			pSAInfo = Fetch(prevTime, level(kHeight, 0), SAParam, forecast_type(kAnalysis),
			                itsConfiguration->SourceGeomNames(), producer(107, 86, 107, "LAPSFIN"), false);
			pDAInfo = Fetch(prevTime, level(kHeight, 0), DAParam, forecast_type(kAnalysis),
			                itsConfiguration->SourceGeomNames(), producer(107, 86, 107, "LAPSFIN"), false);

			if (pSAInfo && pDAInfo)
			{
				break;
			}

			prevTime.ValidDateTime().Adjust(kHourResolution, -1);
			prevTime.OriginDateTime(prevTime.ValidDateTime());
		}
	}
	else
	{
		pSAInfo = Fetch(prevTime, level(kHeight, 0), SAParam, forecastType, false);
		pDAInfo = Fetch(prevTime, level(kHeight, 0), DAParam, forecastType, false);
	}

	if (!pSAInfo || !pDAInfo)
	{
		if (prod.Id() != 107)
		{
			myThreadedLogger.Error("DA and SA not found from obs producer");
			return;
		}
		// If we don't have a history of sa & da, start accumulating
		// it but do not write snow index.

		std::vector<double> pSA(myTargetInfo->Grid()->Size(), 0.0);
		std::vector<double> pDA = pSA;

		myThreadedLogger.Warning("Spinup phase, producing only DA and SA");
		CalculateSnowDriftIndex(myTargetInfo, VEC(TInfo), VEC(FFInfo), VEC(SFInfo), pSA, pDA);

		myTargetInfo->Find<param>(SDIParam);
		myTargetInfo->Data().Fill(MissingDouble());
	}
	else
	{
		CalculateSnowDriftIndex(myTargetInfo, VEC(TInfo), VEC(FFInfo), VEC(SFInfo), VEC(pSAInfo), VEC(pDAInfo));
	}

	myThreadedLogger.Info("[" + deviceType + "] Missing: " + std::to_string(util::MissingPercent(*myTargetInfo)) + "%");
}

double DriftMagnitude(double ff, double mi)
{
	return (ff * ff * ff / 1728.0) * mi;
}

double DriftIndex(double sv)
{
	if (sv < 0.09)
	{
		return 0;  // no drift
	}
	else if (sv < 0.21)
	{
		return 1;  // low
	}
	else if (sv < 0.5)
	{
		return 2;  // moderate
	}
	else
	{
		return 3;  // high
	}
}

double MobilityIndex(double da, double sa)
{
	double mi = 1.0;

	if (da < 2.0 && sa < 24.0)
	{
		mi = 1.0;
	}
	else if (da >= 2.0 && da <= 6.0)
	{
		mi = 0.6;
	}
	else if (da > 6.0)
	{
		mi = 0.3;
	}

	if (sa >= 24.0 && mi == 1.0)
	{
		mi = 0.6;
	}

	return mi;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svtdata.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2007-04-26 09:41:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SVTOOLS_SVTDATA_HXX
#define _SVTOOLS_SVTDATA_HXX

#ifndef _TOOLS_RESID_HXX
#include <tools/resid.hxx>
#endif
#ifndef _TOOLS_SIMPLERESMGR_HXX_
#include <tools/simplerm.hxx>
#endif

class ResMgr;
class SfxItemDesruptorList_Impl;
class SfxItemPool;
class Twain;

//============================================================================
class ImpSvtData
{
public:
    Twain * pTwain;
    const SfxItemPool * pStoringPool;
    SfxItemDesruptorList_Impl * pItemDesruptList;

    ResMgr *        pResMgr;
    ResMgr *        pPatchResMgr;

    void*           m_pThreadsafeRMs;
        // one SimpleResMgr for each language for which a resource was requested
        // (When using the 'non-simple' resmgr, the first request for any language wins, any
        // further request for any other language supply the resmgr of the first call.
        // For the simple resmgr we have a mgr for each language ever requested).

private:
    ImpSvtData():
        pTwain(0), pStoringPool(0), pItemDesruptList(0), pResMgr(0),
        pPatchResMgr(NULL), m_pThreadsafeRMs(NULL)
    {}

    ~ImpSvtData();

public:
    ResMgr * GetResMgr(const ::com::sun::star::lang::Locale aLocale);
    ResMgr * GetResMgr(); // VCL dependant, only available in SVT, not in SVL!

    ResMgr * GetPatchResMgr();
    ResMgr * GetPatchResMgr(const ::com::sun::star::lang::Locale& aLocale);

    SimpleResMgr * GetSimpleRM(const ::com::sun::star::lang::Locale& rLocale);

    static ImpSvtData & GetSvtData();
};

//============================================================================

class SvpResId: public ResId
{
public:
    SvpResId( USHORT nId, const ::com::sun::star::lang::Locale aLocale ):
        ResId( nId, *ImpSvtData::GetSvtData().GetResMgr( aLocale ) ) {}

     // VCL dependant, only available in SVT, not in SVL!
    SvpResId( USHORT nId );
};

class SvtResId: public ResId
{
public:
    SvtResId(USHORT nId, const ::com::sun::star::lang::Locale aLocale):
        ResId(nId, *ImpSvtData::GetSvtData().GetResMgr(aLocale)) {}

    SvtResId(USHORT nId): ResId(nId, *ImpSvtData::GetSvtData().GetResMgr()) {}
     // VCL dependant, only available in SVT, not in SVL!
};

//============================================================================
class SvtSimpleResId
{
    String  m_sValue;

public:
    SvtSimpleResId(USHORT nId, const ::com::sun::star::lang::Locale aLocale) : m_sValue(ImpSvtData::GetSvtData().GetSimpleRM(aLocale)->ReadString(nId)) { };

    operator String () const { return m_sValue; }
};

#endif //  _SVTOOLS_SVTDATA_HXX

<commit_msg>INTEGRATION: CWS changefileheader (1.3.302); FILE MERGED 2008/04/01 15:44:35 thb 1.3.302.2: #i85898# Stripping all external header guards 2008/03/31 13:01:09 rt 1.3.302.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: svtdata.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SVTOOLS_SVTDATA_HXX
#define _SVTOOLS_SVTDATA_HXX

#include <tools/resid.hxx>
#include <tools/simplerm.hxx>

class ResMgr;
class SfxItemDesruptorList_Impl;
class SfxItemPool;
class Twain;

//============================================================================
class ImpSvtData
{
public:
    Twain * pTwain;
    const SfxItemPool * pStoringPool;
    SfxItemDesruptorList_Impl * pItemDesruptList;

    ResMgr *        pResMgr;
    ResMgr *        pPatchResMgr;

    void*           m_pThreadsafeRMs;
        // one SimpleResMgr for each language for which a resource was requested
        // (When using the 'non-simple' resmgr, the first request for any language wins, any
        // further request for any other language supply the resmgr of the first call.
        // For the simple resmgr we have a mgr for each language ever requested).

private:
    ImpSvtData():
        pTwain(0), pStoringPool(0), pItemDesruptList(0), pResMgr(0),
        pPatchResMgr(NULL), m_pThreadsafeRMs(NULL)
    {}

    ~ImpSvtData();

public:
    ResMgr * GetResMgr(const ::com::sun::star::lang::Locale aLocale);
    ResMgr * GetResMgr(); // VCL dependant, only available in SVT, not in SVL!

    ResMgr * GetPatchResMgr();
    ResMgr * GetPatchResMgr(const ::com::sun::star::lang::Locale& aLocale);

    SimpleResMgr * GetSimpleRM(const ::com::sun::star::lang::Locale& rLocale);

    static ImpSvtData & GetSvtData();
};

//============================================================================

class SvpResId: public ResId
{
public:
    SvpResId( USHORT nId, const ::com::sun::star::lang::Locale aLocale ):
        ResId( nId, *ImpSvtData::GetSvtData().GetResMgr( aLocale ) ) {}

     // VCL dependant, only available in SVT, not in SVL!
    SvpResId( USHORT nId );
};

class SvtResId: public ResId
{
public:
    SvtResId(USHORT nId, const ::com::sun::star::lang::Locale aLocale):
        ResId(nId, *ImpSvtData::GetSvtData().GetResMgr(aLocale)) {}

    SvtResId(USHORT nId): ResId(nId, *ImpSvtData::GetSvtData().GetResMgr()) {}
     // VCL dependant, only available in SVT, not in SVL!
};

//============================================================================
class SvtSimpleResId
{
    String  m_sValue;

public:
    SvtSimpleResId(USHORT nId, const ::com::sun::star::lang::Locale aLocale) : m_sValue(ImpSvtData::GetSvtData().GetSimpleRM(aLocale)->ReadString(nId)) { };

    operator String () const { return m_sValue; }
};

#endif //  _SVTOOLS_SVTDATA_HXX

<|endoftext|>


<commit_before>#include <cstdarg>
#include <cstring>
#include <numeric>
#include <limits>

#include "calculate.h"
#include "calculate/c-interface.h"

#define cast(expression) reinterpret_cast<Expression>(expression)
#define uncast(expression) reinterpret_cast<Calculate*>(expression)

namespace calculate_c_interface {
    using namespace calculate;

    Expression createExpression(const char *expr, const char *vars,
                                char *error) {
        try {
            auto expr_obj = cast(new Calculate(expr, vars));
            strcpy(error, "");
            return expr_obj;
        }
        catch (const BaseCalculateException &e) {
            strcpy(error, e.what());
        }

        return nullptr;
    }

    Expression newExpression(const char *expr, const char *vars) {
        char error[64];

        return createExpression(expr, vars, error);
    }

    void freeExpression(Expression expr) {
        if (expr)
            delete uncast(expr);
    }

    int compare(Expression one, Expression another) {
        if (one && another)
            return (uncast(one)->operator==(*uncast(another))) ? 1 : 0;

        return -1;
    }

    const char* getExpression(Expression expr) {
        return expr ? uncast(expr)->expression().c_str() : "";
    }

    const char* getVariables(Expression expr) {
        static String vars;

        const auto &variables = uncast(expr)->variables();
        if (expr && variables.size()) {
            vars = std::accumulate(
                variables.begin() + 1,
                variables.end(),
                variables[0],
                [](const String &accumulator, const String &next) {
                    return accumulator + "," + next;
                }
            );
        }
        else {
            vars = String();
        }
        return vars.c_str();
    }

    double evaluateArray(Expression expr, double *args, int size,
                         char *error) {
        if (!expr)
            return std::numeric_limits<double>::quiet_NaN();

        vValue values(args, args + size);
        try {
            strcpy(error, "");
            return uncast(expr)->operator()(values);
        }
        catch (const BaseCalculateException &e) {
            strcpy(error, e.what());
        }

        return std::numeric_limits<double>::quiet_NaN();
    }

    double evalArray(Expression expr, double *args, int size) {
        char error[64];

        return evaluateArray(expr, args, size, error);
    }

    double eval(Expression expr, ...) {
        if (!expr)
            return std::numeric_limits<double>::quiet_NaN();

        auto vars = uncast(expr)->variables().size();
        vValue values;
        va_list list;
        va_start(list, expr);
        for (auto i = 0u; i < vars; i++)
            values.push_back(va_arg(list, double));
        va_end(list);

        return uncast(expr)->operator()(values);
    }

}

extern "C" const calculate_c_library_template Calculate = {
    calculate_c_interface::createExpression,
    calculate_c_interface::newExpression,
    calculate_c_interface::freeExpression,
    calculate_c_interface::compare,
    calculate_c_interface::getExpression,
    calculate_c_interface::getVariables,
    calculate_c_interface::evaluateArray,
    calculate_c_interface::evalArray,
    calculate_c_interface::eval
};
<commit_msg>Fixed silent error<commit_after>#include <cstdarg>
#include <cstring>
#include <numeric>
#include <limits>

#include "calculate.h"
#include "calculate/c-interface.h"

#define cast(expression) reinterpret_cast<Expression>(expression)
#define uncast(expression) reinterpret_cast<Calculate*>(expression)

namespace calculate_c_interface {
    using namespace calculate;

    Expression createExpression(const char *expr, const char *vars,
                                char *error) {
        try {
            auto expr_obj = cast(new Calculate(expr, vars));
            strcpy(error, "");
            return expr_obj;
        }
        catch (const BaseCalculateException &e) {
            strcpy(error, e.what());
        }

        return nullptr;
    }

    Expression newExpression(const char *expr, const char *vars) {
        char error[64];

        return createExpression(expr, vars, error);
    }

    void freeExpression(Expression expr) {
        if (expr)
            delete uncast(expr);
    }

    int compare(Expression one, Expression another) {
        if (one && another)
            return (uncast(one)->operator==(*uncast(another))) ? 1 : 0;

        return -1;
    }

    const char* getExpression(Expression expr) {
        return expr ? uncast(expr)->expression().c_str() : "";
    }

    const char* getVariables(Expression expr) {
        static String vars;

        const auto &variables = uncast(expr)->variables();
        if (expr && variables.size()) {
            vars = std::accumulate(
                variables.begin() + 1,
                variables.end(),
                variables[0],
                [](const String &accumulator, const String &next) {
                    return accumulator + "," + next;
                }
            );
        }
        else {
            vars = String();
        }
        return vars.c_str();
    }

    double evaluateArray(Expression expr, double *args, int size,
                         char *error) {
        if (!expr) {
            strcpy(error, "Not initialized");
            return std::numeric_limits<double>::quiet_NaN();
        }

        vValue values(args, args + size);
        try {
            strcpy(error, "");
            return uncast(expr)->operator()(values);
        }
        catch (const BaseCalculateException &e) {
            strcpy(error, e.what());
        }

        return std::numeric_limits<double>::quiet_NaN();
    }

    double evalArray(Expression expr, double *args, int size) {
        char error[64];

        return evaluateArray(expr, args, size, error);
    }

    double eval(Expression expr, ...) {
        if (!expr)
            return std::numeric_limits<double>::quiet_NaN();

        auto vars = uncast(expr)->variables().size();
        vValue values;
        va_list list;
        va_start(list, expr);
        for (auto i = 0u; i < vars; i++)
            values.push_back(va_arg(list, double));
        va_end(list);

        return uncast(expr)->operator()(values);
    }

}

extern "C" const calculate_c_library_template Calculate = {
    calculate_c_interface::createExpression,
    calculate_c_interface::newExpression,
    calculate_c_interface::freeExpression,
    calculate_c_interface::compare,
    calculate_c_interface::getExpression,
    calculate_c_interface::getVariables,
    calculate_c_interface::evaluateArray,
    calculate_c_interface::evalArray,
    calculate_c_interface::eval
};
<|endoftext|>


<commit_before>// timing - rlyeh, public domain [ref] https://gist.github.com/r-lyeh/07cc318dbeee9b616d5e {
#pragma once
#include <thread>
#include <chrono>
#if !defined(TIMING_USE_OMP) && ( defined(USE_OMP) || defined(_MSC_VER) /*|| defined(__ANDROID_API__)*/ )
#   define TIMING_USE_OMP
#   include <omp.h>
#endif
struct timing {
    static double now() {
#   ifdef TIMING_USE_OMP
        static auto const epoch = omp_get_wtime();
        return omp_get_wtime() - epoch;
#   else
        static auto const epoch = std::chrono::steady_clock::now(); // milli ms > micro us > nano ns
        return std::chrono::duration_cast< std::chrono::microseconds >( std::chrono::steady_clock::now() - epoch ).count() / 1000000.0;
#   endif
    }
    template<typename FN>
    static double bench( const FN &fn ) {
        auto took = -now();
        return ( fn(), took + now() );
    }
    static void sleep( double secs ) {
        std::chrono::microseconds duration( (int)(secs * 1000000) );
        std::this_thread::sleep_for( duration );
    }
};
// } timing

#include <algorithm>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <fstream>
#include <set>
#include <map>
#include <vector>
#include <sstream>

#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

std::string base( const std::string &app = std::string() ) {
    TCHAR dest[MAX_PATH];
    size_t destSize = MAX_PATH;

    if (!dest) return "./" + app;
    if (MAX_PATH > destSize) return "./" + app;

    DWORD length = GetModuleFileName( NULL, dest, destSize );
    PathRemoveFileSpec(dest);

    for( auto &ch : dest ) {
        if( ch == '\\' ) ch = '/';
    }

    return std::string() + dest + "/" + app;
}

int main( int argc, const char **argv ) {
    int ret = 0;

    // benchmark
    if( argc > 1 )
    {
        int N = 0;
        std::string cmd, sep, desc;
        for( int i = 1; i < argc; ++i ) {
            if( argv[i][0] >= '0' && argv[i][0] <= '9' ) {
                 N = std::strtoul( argv[i], NULL, NULL );
            }
            else
            if( argv[i][0] == '/' && argv[i][1] == '/' ) {
                desc = &argv[i][2];
            }
            else {
                cmd += sep + argv[i];
                sep = ' ';

                if( desc.empty() ) desc = argv[i];
            }
        }
        auto overhead = 0; // measure fib(0)
        auto took = timing::bench( [&]{
            // avg time
            for( auto i = 0; i < N - 1; ++i )
            system((cmd+" 1> nul 2> nul").c_str());
            ret = system(cmd.c_str());
        } );
        std::cout << (std::abs(took - overhead) / N) << " s." << std::endl;

        // append to 'bench.csv'
        {
            std::ofstream ofs( base("/bench.csv").c_str(), std::ios::binary | std::ios::app );
            if( ofs.good() ) {
                ofs << desc << "," << ( std::abs(took - overhead) / N ) << "\r\n"; //std::endl;
            }
        }
    }

    // update 'bench.md'
    {
        auto tokenize = []( const std::string &self, const std::string &delimiters ) -> std::vector< std::string > {
            std::string map( 256, '\0' );
            for( auto &ch : delimiters )
                map[ ch ] = '\1';
            std::vector< std::string > tokens(1);
            for( const unsigned char &ch : self ) {
                /**/ if( !map.at(ch)          ) tokens.back().push_back( ch );
                else if( tokens.back().size() ) tokens.push_back( std::string() );
            }
            while( tokens.size() && !tokens.back().size() ) tokens.pop_back();
            return tokens;
        };

        struct idx {
            std::string name;
            float time;

            float relative_speed( float min, float max ) const {
                float tstep = time / min;
                return 100 / (tstep);
            }

            bool operator <( const idx &other ) const {
                if( time < other.time ) return true;
                return name < other.name;
            }

            bool operator==( const idx &other ) const {
                return name == other.name;
            }
            bool operator!=( const idx &other ) const {
                return name != other.name;
            }
        };

        std::map< std::string, float > unique;
        std::set< idx > sort;

        {
            std::ifstream ifs( base("/bench.csv").c_str(), std::ios::binary);
            std::stringstream ss;
            ss << ifs.rdbuf();
            auto lines = tokenize( ss.str(), "\r\n" );
            for( auto &line : lines ) {
                for( auto &ch : line ) {
                    if( ch == '\\' ) ch = '/';
                }
                auto tokens = tokenize( line, "," );
                if( tokens.size() == 3 ) {
                    if( tokens[1] == "fib" || tokens[1] == "fib.exe" ) tokens[1] = "c/vc";
                    float time = std::strtof( tokens[2].c_str(), NULL );
                    tokens[1] = tokens[0] + "|" + tokens[1];
                    float prev = (unique[ tokens[1] ] = unique[ tokens[1] ]);
                    unique[ tokens[1] ] = prev ? (std::min)( prev, time ) : time;
                }
            }
            for( auto &it : unique ) {
                sort.insert( idx{ it.first, it.second } );
            }
        }

        auto min = float(sort.begin()->time);
        auto max = float(sort.rbegin()->time);

#if 1
        auto cmin = sort.begin(); //find("lua")->time; //float(sort.begin()->time);
        while( cmin != sort.end() && cmin->name.find("[lua]") == std::string::npos ) cmin++;
        min = float(cmin->time);
#endif

        std::ofstream ofs( base("BENCH.md").c_str(), std::ios::binary);
        ofs << "|Rank|Language|Flavor|Time|Relative Lua speed|Score|" << std::endl;
        ofs << "|---:|:-------|:-----|---:|:----------------:|----:|" << std::endl;
        auto rank = 0;
        for( auto &it : sort ) {
            float speed = it.relative_speed(min, max);
            int score( speed );
            int factor( speed / 100 );
            speed = speed > 100 ? 100 : speed;
            char time_str[16];   sprintf(time_str, "%6.3f", it.time);
            char factor_str[16]; sprintf(factor_str, "%02d.%01d", score/100, (score%100) / 10 );

            ofs << '|' << (++rank) << '|' << it.name << "|" << time_str << " s.|![" << speed << "%](http://progressed.io/bar/" << int(speed);

            if( score > 100 ) {
                ofs << "?title=x" << factor_str << ")|" << score << " pt|" << std::endl;
            } else {
                ofs << ")|" << score << " pt|" << std::endl;
            }
        }
    }

    return ret;
}
<commit_msg>fix #5<commit_after>// timing - rlyeh, public domain [ref] https://gist.github.com/r-lyeh/07cc318dbeee9b616d5e {
#pragma once
#include <thread>
#include <chrono>
#if !defined(TIMING_USE_OMP) && ( defined(USE_OMP) || defined(_MSC_VER) /*|| defined(__ANDROID_API__)*/ )
#   define TIMING_USE_OMP
#   include <omp.h>
#endif
struct timing {
    static double now() {
#   ifdef TIMING_USE_OMP
        static auto const epoch = omp_get_wtime();
        return omp_get_wtime() - epoch;
#   else
        static auto const epoch = std::chrono::steady_clock::now(); // milli ms > micro us > nano ns
        return std::chrono::duration_cast< std::chrono::microseconds >( std::chrono::steady_clock::now() - epoch ).count() / 1000000.0;
#   endif
    }
    template<typename FN>
    static double bench( const FN &fn ) {
        auto took = -now();
        return ( fn(), took + now() );
    }
    static void sleep( double secs ) {
        std::chrono::microseconds duration( (int)(secs * 1000000) );
        std::this_thread::sleep_for( duration );
    }
};
// } timing

#include <algorithm>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <fstream>
#include <set>
#include <map>
#include <vector>
#include <sstream>
#include <stdexcept>

#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

std::string base( const std::string &app = std::string() ) {
    TCHAR dest[MAX_PATH];
    size_t destSize = MAX_PATH;

    if (!dest) return "./" + app;
    if (MAX_PATH > destSize) return "./" + app;

    DWORD length = GetModuleFileName( NULL, dest, destSize );
    PathRemoveFileSpec(dest);

    for( auto &ch : dest ) {
        if( ch == '\\' ) ch = '/';
    }

    return std::string() + dest + "/" + app;
}

int main( int argc, const char **argv ) try {
    int ret = 0;

    // benchmark
    if( argc > 1 )
    {
        int N = 0;
        std::string cmd, sep, desc;
        for( int i = 1; i < argc; ++i ) {
            if( argv[i][0] >= '0' && argv[i][0] <= '9' ) {
                 N = std::strtoul( argv[i], NULL, NULL );
            }
            else
            if( argv[i][0] == '/' && argv[i][1] == '/' ) {
                desc = &argv[i][2];
            }
            else {
                cmd += sep + argv[i];
                sep = ' ';

                if( desc.empty() ) desc = argv[i];
            }
        }
        auto overhead = 0; // measure fib(0)
        auto took = timing::bench( [&]{
            // avg time
            for( auto i = 0; i < N - 1; ++i )
            system((cmd+" 1> nul 2> nul").c_str());
            ret = system(cmd.c_str());
        } );
        std::cout << (std::abs(took - overhead) / N) << " s." << std::endl;

        // append to 'bench.csv'
        {
            std::ofstream ofs( base("/bench.csv").c_str(), std::ios::binary | std::ios::app );
            if( ofs.good() ) {
                ofs << desc << "," << ( std::abs(took - overhead) / N ) << "\r\n"; //std::endl;
            }
        }
    }

    // update 'bench.md'
    {
        auto tokenize = []( const std::string &self, const std::string &delimiters ) -> std::vector< std::string > {
            std::string map( 256, '\0' );
            for( auto &ch : delimiters )
                map[ ch ] = '\1';
            std::vector< std::string > tokens(1);
            for( const unsigned char &ch : self ) {
                /**/ if( !map.at(ch)          ) tokens.back().push_back( ch );
                else if( tokens.back().size() ) tokens.push_back( std::string() );
            }
            while( tokens.size() && !tokens.back().size() ) tokens.pop_back();
            return tokens;
        };

        struct idx {
            std::string name;
            float time;

            float relative_speed( float min, float max ) const {
                float tstep = time / min;
                return 100 / (tstep);
            }

            bool operator <( const idx &other ) const {
                if( time < other.time ) return true;
                return name < other.name;
            }

            bool operator==( const idx &other ) const {
                return name == other.name;
            }
            bool operator!=( const idx &other ) const {
                return name != other.name;
            }
        };

        std::map< std::string, float > unique;
        std::set< idx > sort;

        {
            std::ifstream ifs( base("/bench.csv").c_str(), std::ios::binary);
            std::stringstream ss;
            ss << ifs.rdbuf();
            auto lines = tokenize( ss.str(), "\r\n" );
            for( auto &line : lines ) {
                for( auto &ch : line ) {
                    if( ch == '\\' ) ch = '/';
                }
                auto tokens = tokenize( line, "," );
                if( tokens.size() == 3 ) {
                    if( tokens[1] == "fib" || tokens[1] == "fib.exe" ) tokens[1] = "c/vc";
                    float time = std::strtof( tokens[2].c_str(), NULL );
                    tokens[1] = tokens[0] + "|" + tokens[1];
                    float prev = (unique[ tokens[1] ] = unique[ tokens[1] ]);
                    unique[ tokens[1] ] = prev ? (std::min)( prev, time ) : time;
                }
            }
            for( auto &it : unique ) {
                sort.insert( idx{ it.first, it.second } );
            }
        }

        auto min = float(sort.begin()->time);
        auto max = float(sort.rbegin()->time);

#if 1
        auto cmin = sort.begin(); //find("lua")->time; //float(sort.begin()->time);
        while( cmin != sort.end() && cmin->name.find("[lua]") == std::string::npos ) cmin++;
        min = float(cmin->time);
#endif

        std::ofstream ofs( base("BENCH.md").c_str(), std::ios::binary);
        ofs << "|Rank|Language|Flavor|Time|Relative Lua speed|Score|" << std::endl;
        ofs << "|---:|:-------|:-----|---:|:----------------:|----:|" << std::endl;
        auto rank = 0;
        for( auto &it : sort ) {
            float speed = it.relative_speed(min, max);
            int score( speed );
            int factor( speed / 100 );
            speed = speed > 100 ? 100 : speed;
            char time_str[16];   sprintf(time_str, "%6.3f", it.time);
            char factor_str[16]; sprintf(factor_str, "%02d.%01d", score/100, (score%100) / 10 );

            ofs << '|' << (++rank) << '|' << it.name << "|" << time_str << " s.|![" << speed << "%](http://progressed.io/bar/" << int(speed);

            if( score > 100 ) {
                ofs << "?title=x" << factor_str << ")|" << score << " pt|" << std::endl;
            } else {
                ofs << ")|" << score << " pt|" << std::endl;
            }
        }
    }

    return ret;
}
catch( std::exception &e ) {
    puts( "error: exception caught" );
    puts( e.what() );
    return -1;
}
catch(...) {
    puts( "error: exception caught" );
    return -1;
}
<|endoftext|>


<commit_before>#include "Profiler.h"
#include <avr/interrupt.h>

static volatile uint16_t profileIpBuf[256];
static volatile uint8_t profileIdx = 0;

static bool addedTask = false;
Task profilingTask(300, sendProfilingData);

void sendProfilingData() {
  disableProfiling();

  uint16_t ipBuf[256];
  m_memcpy(ipBuf, (void *)profileIpBuf, sizeof(ipBuf));
  m_memclr((void *)profileIpBuf, sizeof(profileIpBuf));
  profileIdx = 0;

  MidiUart.putc(0xF0);
  MidiUart.putc(0x01);
  for (int i = 0; i < 256; i++) {
    MidiUart.putc((ipBuf[i] >> 14) & 0x7F);
    MidiUart.putc((ipBuf[i] >> 7) & 0x7F);
    MidiUart.putc((ipBuf[i] >> 0) & 0x7F);
  }
  MidiUart.putc(0xF7);
  enableProfiling();
}

void enableProfiling() {
  SET_BIT(TIMSK, TOIE0);
  if (!addedTask) {
    GUI.addTask(&profilingTask);
    addedTask = true;
  }
}

void disableProfiling() {
  CLEAR_BIT(TIMSK, TOIE0);
}

static uint8_t profileCnt0 = 255;
ISR(TIMER0_OVF_vect) {
  uint16_t fp = (uint16_t)__builtin_frame_address(0);
  uint8_t a, b;
  fp += 12;
  a = (*((uint8_t *)fp));
  b = *((uint8_t *)(fp + 1));
  //  a <<= 1;
  //  b <<= 1;
  uint16_t address = ((a << 8) | b) << 1;
  //  uint16_t address = (((a << 1) & 0xFF) << 8 | ((b << 1) & 0xFF));
  // uint16_t address = (a << 8) | b;
  profileIpBuf[(profileIdx++)] = address;

  // avoid aliasing
  profileCnt0--;
  if (profileCnt0 < 128) {
    profileCnt0 = 255;
  }
  TCNT0 = profileCnt0;
}
<commit_msg>Add missing includes to profiler<commit_after>#include "Profiler.h"
#include "GUI.h"
#include "MidiUart.h"
#include <avr/interrupt.h>

static volatile uint16_t profileIpBuf[256];
static volatile uint8_t profileIdx = 0;

static bool addedTask = false;
Task profilingTask(300, sendProfilingData);

void sendProfilingData() {
  disableProfiling();

  uint16_t ipBuf[256];
  m_memcpy(ipBuf, (void *)profileIpBuf, sizeof(ipBuf));
  m_memclr((void *)profileIpBuf, sizeof(profileIpBuf));
  profileIdx = 0;

  MidiUart.putc(0xF0);
  MidiUart.putc(0x01);
  for (int i = 0; i < 256; i++) {
    MidiUart.putc((ipBuf[i] >> 14) & 0x7F);
    MidiUart.putc((ipBuf[i] >> 7) & 0x7F);
    MidiUart.putc((ipBuf[i] >> 0) & 0x7F);
  }
  MidiUart.putc(0xF7);
  enableProfiling();
}

void enableProfiling() {
  SET_BIT(TIMSK, TOIE0);
  if (!addedTask) {
    GUI.addTask(&profilingTask);
    addedTask = true;
  }
}

void disableProfiling() {
  CLEAR_BIT(TIMSK, TOIE0);
}

static uint8_t profileCnt0 = 255;
ISR(TIMER0_OVF_vect) {
  uint16_t fp = (uint16_t)__builtin_frame_address(0);
  uint8_t a, b;
  fp += 12;
  a = (*((uint8_t *)fp));
  b = *((uint8_t *)(fp + 1));
  //  a <<= 1;
  //  b <<= 1;
  uint16_t address = ((a << 8) | b) << 1;
  //  uint16_t address = (((a << 1) & 0xFF) << 8 | ((b << 1) & 0xFF));
  // uint16_t address = (a << 8) | b;
  profileIpBuf[(profileIdx++)] = address;

  // avoid aliasing
  profileCnt0--;
  if (profileCnt0 < 128) {
    profileCnt0 = 255;
  }
  TCNT0 = profileCnt0;
}
<|endoftext|>


<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/

/* See genQuery.h for a description of this API call.*/

#include "reFuncDefs.hpp"
#include "genQuery.hpp"
#include "icatHighLevelRoutines.hpp"
#include "miscUtil.hpp"
#include "cache.hpp"
#include "rsGlobalExtern.hpp"
#include "irods_server_properties.hpp"

#include "boost/format.hpp"
#include <string>

static
irods::error strip_new_query_terms(
    genQueryInp_t* _inp ) {
    // =-=-=-=-=-=-=-
    // cache pointers to the incoming inxIvalPair
    inxIvalPair_t tmp;
    tmp.len   = _inp->selectInp.len;
    tmp.inx   = _inp->selectInp.inx;
    tmp.value = _inp->selectInp.value;

    // =-=-=-=-=-=-=-
    // zero out the selectInp to copy
    // fresh community indices and values
    bzero( &_inp->selectInp, sizeof( _inp->selectInp ) );

    // =-=-=-=-=-=-=-
    // iterate over the tmp and only copy community values
    for ( int i = 0; i < tmp.len; ++i ) {
        if ( tmp.inx[ i ] == COL_R_RESC_CHILDREN ||
                tmp.inx[ i ] == COL_R_RESC_CONTEXT  ||
                tmp.inx[ i ] == COL_R_RESC_PARENT   ||
                tmp.inx[ i ] == COL_R_RESC_OBJCOUNT ||
                tmp.inx[ i ] == COL_D_RESC_HIER ) {
            continue;
        }
        else {
            addInxIval( &_inp->selectInp, tmp.inx[ i ], tmp.value[ i ] );
        }

    } // for i

    return SUCCESS();

} // strip_new_query_terms

static
irods::error strip_deprecated_query_terms(
    genQueryInp_t* _inp ) {

	const int COL_D_RESC_GROUP_NAME  = 408;

    // =-=-=-=-=-=-=-
    // cache pointers to the incoming inxIvalPair
    inxIvalPair_t tmp;
    tmp.len   = _inp->selectInp.len;
    tmp.inx   = _inp->selectInp.inx;
    tmp.value = _inp->selectInp.value;

    // =-=-=-=-=-=-=-
    // zero out the selectInp to copy
    // fresh indices and values
    bzero( &_inp->selectInp, sizeof( _inp->selectInp ) );

    // =-=-=-=-=-=-=-
    // iterate over tmp and skip deprecated values
    for ( int i = 0; i < tmp.len; ++i ) {
        if ( tmp.inx[ i ] == COL_D_RESC_GROUP_NAME ) {
            continue;
        }
        else {
            addInxIval( &_inp->selectInp, tmp.inx[ i ], tmp.value[ i ] );
        }

    } // for i

    return SUCCESS();

} // strip_deprecated_query_terms

static
irods::error proc_query_terms_for_community_server(
    const std::string& _zone_hint,
    genQueryInp_t*     _inp ) {
    bool        done     = false;
    zoneInfo_t* tmp_zone = ZoneInfoHead;
    // =-=-=-=-=-=-=-
    // if the zone hint starts with a / we
    // will need to pull out just the zone
    std::string zone_hint = _zone_hint;
    if ( _zone_hint[0] == '/' ) {
        size_t pos = _zone_hint.find( "/", 1 );
        if ( std::string::npos != pos ) {
            zone_hint = _zone_hint.substr( 1, pos - 1 );
        }
        else {
            zone_hint = _zone_hint.substr( 1 );
        }

    }
    else {
        return SUCCESS();
    }

    // =-=-=-=-=-=-=-
    // grind through the zones and find the match to the kw
    while ( !done && tmp_zone ) {
        if ( zone_hint == tmp_zone->zoneName               &&
                tmp_zone->masterServerHost->conn              &&
                tmp_zone->masterServerHost->conn->svrVersion &&
                tmp_zone->masterServerHost->conn->svrVersion->cookie < 301 ) {
            return strip_new_query_terms( _inp );

        }
        else {
            tmp_zone = tmp_zone->next;

        }
    }

    return SUCCESS();

} // proc_query_terms_for_community_server

/* can be used for debug: */
/* extern int printGenQI( genQueryInp_t *genQueryInp); */
;
int
rsGenQuery( rsComm_t *rsComm, genQueryInp_t *genQueryInp,
            genQueryOut_t **genQueryOut ) {
    rodsServerHost_t *rodsServerHost;
    int status;
    char *zoneHint;
    zoneHint = getZoneHintForGenQuery( genQueryInp );

    std::string zone_hint_str;
    if ( zoneHint ) {
        zone_hint_str = zoneHint;
    }

    status = getAndConnRcatHost( rsComm, SLAVE_RCAT, ( const char* )zoneHint,
                                 &rodsServerHost );

    if ( status < 0 ) {
        return status;
    }

    // =-=-=-=-=-=-=-
    // handle connections with community iRODS
    if ( !zone_hint_str.empty() ) {
        irods::error ret = proc_query_terms_for_community_server( zone_hint_str, genQueryInp );
        if ( !ret.ok() ) {
            irods::log( PASS( ret ) );
        }
    }

    // =-=-=-=-=-=-=-
    // handle queries from older clients
    std::string client_rel_version = rsComm->cliVersion.relVersion;
    std::string local_rel_version = RODS_REL_VERSION;
    if (client_rel_version != local_rel_version) {	// skip if version strings match
    	strip_deprecated_query_terms( genQueryInp );
    }

    if ( rodsServerHost->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsGenQuery( rsComm, genQueryInp, genQueryOut );
#else
        rodsLog( LOG_NOTICE,
                 "rsGenQuery error. RCAT is not configured on this host" );
        return SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        // =-=-=-=-=-=-=-
        // strip disable strict acl flag if the agent conn flag is missing
        char* dis_kw = getValByKey( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );
        if ( dis_kw ) {
            irods::server_properties& props = irods::server_properties::getInstance();
            props.capture_if_needed();

            std::string svr_sid;
            irods::error err = props.get_property< std::string >( irods::AGENT_CONN_KW, svr_sid );
            if ( !err.ok() ) {
                rmKeyVal( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );

            }

        } // if dis_kw

        status = rcGenQuery( rodsServerHost->conn,
                             genQueryInp, genQueryOut );
    }
    if ( status < 0  && status != CAT_NO_ROWS_FOUND ) {
        std::string prefix = ( rodsServerHost->localFlag == LOCAL_HOST ) ? "_rs" : "rc";
        rodsLog( LOG_NOTICE,
                 "rsGenQuery: %sGenQuery failed, status = %d", prefix.c_str(), status );
    }
    return status;
}

#ifdef RODS_CAT
int
_rsGenQuery( rsComm_t *rsComm, genQueryInp_t *genQueryInp,
             genQueryOut_t **genQueryOut ) {
    int status;

    static int ruleExecuted = 0;
    ruleExecInfo_t rei;

    static int PrePostProcForGenQueryFlag = -2;
    int i, argc;
    ruleExecInfo_t rei2;
    const char *args[MAX_NUM_OF_ARGS_IN_ACTION];

    if ( PrePostProcForGenQueryFlag < 0 ) {
        if ( getenv( "PREPOSTPROCFORGENQUERYFLAG" ) != NULL ) {
            PrePostProcForGenQueryFlag = 1;
        }
        else {
            PrePostProcForGenQueryFlag = 0;
        }
    }

    memset( ( char* )&rei2, 0, sizeof( ruleExecInfo_t ) );
    rei2.rsComm = rsComm;
    if ( rsComm != NULL ) {
        rei2.uoic = &rsComm->clientUser;
        rei2.uoip = &rsComm->proxyUser;
    }

    /*  printGenQI(genQueryInp);  for debug */

    *genQueryOut = ( genQueryOut_t* )malloc( sizeof( genQueryOut_t ) );
    memset( ( char * )*genQueryOut, 0, sizeof( genQueryOut_t ) );

    if ( ruleExecuted == 0 ) {
        memset( ( char* )&rei, 0, sizeof( rei ) );
        rei.rsComm = rsComm;
        if ( rsComm != NULL ) {
            /* Include the user info for possible use by the rule.  Note
            that when this is called (as the agent is initializing),
            this user info is not confirmed yet.  For password
            authentication though, the agent will soon exit if this
            is not valid.  But for GSI, the user information may not
            be present and/or may be changed when the authentication
            completes, so it may not be safe to use this in a GSI
            enabled environment.  This addition of user information
            was requested by ARCS/IVEC (Sean Fleming) to avoid a
            local patch.
            */
            rei.uoic = &rsComm->clientUser;
            rei.uoip = &rsComm->proxyUser;
        }

        if ( getRuleEngineStatus() == UNINITIALIZED ) {
            /* Skip the call to run acAclPolicy if the Rule Engine
               hasn't been initialized yet, which happens for a couple
               initial queries made by the agent when starting up.  The
               new RE logs these types of errors and so this avoids that.
            */
            status = -1;
        }
        else {
            status = applyRule( "acAclPolicy", NULL, &rei, NO_SAVE_REI );
        }
        if ( status == 0 ) {
            ruleExecuted = 1; /* No need to retry next time since it
                             succeeded.  Since this is called at
                             startup, the Rule Engine may not be
                             initialized yet, in which case the
                             default setting is fine and we should
                             retry next time. */
        }
    }

    // =-=-=-=-=-=-=-
    // verify that we are running a query for another agent connection
    irods::server_properties& props = irods::server_properties::getInstance();
    props.capture_if_needed();

    std::string svr_sid;
    irods::error err = props.get_property< std::string >( irods::AGENT_CONN_KW, svr_sid );
    bool agent_conn_flg = err.ok();

    // =-=-=-=-=-=-=-
    // detect if a request for disable of strict acls is made
    int acl_val = -1;
    char* dis_kw = getValByKey( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );
    if ( agent_conn_flg && dis_kw ) {
        acl_val = 0;
    }

    // =-=-=-=-=-=-=-
    // cache the old acl value for reuse later if necessary
    int old_acl_val =  chlGenQueryAccessControlSetup(
                           rsComm->clientUser.userName,
                           rsComm->clientUser.rodsZone,
                           rsComm->clientAddr,
                           rsComm->clientUser.authInfo.authFlag,
                           acl_val );

    if ( PrePostProcForGenQueryFlag == 1 ) {
        std::string arg = str( boost::format( "%ld" ) % ( ( long )genQueryInp ) );
        args[0] = arg.c_str();
        argc = 1;
        i =  applyRuleArg( "acPreProcForGenQuery", args, argc, &rei2, NO_SAVE_REI );
        if ( i < 0 ) {
            rodsLog( LOG_ERROR,
                     "rsGenQuery:acPreProcForGenQuery error,stat=%d", i );
            if ( i != NO_MICROSERVICE_FOUND_ERR ) {
                return i;
            }
        }
    }
    /**  June 1 2009 for pre-post processing rule hooks **/

    status = chlGenQuery( *genQueryInp, *genQueryOut );

    // =-=-=-=-=-=-=-
    // if a disable was requested, repave with old value immediately
    if ( agent_conn_flg && dis_kw ) {
        chlGenQueryAccessControlSetup(
            rsComm->clientUser.userName,
            rsComm->clientUser.rodsZone,
            rsComm->clientAddr,
            rsComm->clientUser.authInfo.authFlag,
            old_acl_val );
    }

    /**  June 1 2009 for pre-post processing rule hooks **/
    if ( PrePostProcForGenQueryFlag == 1 ) {
        std::string in_string = str( boost::format( "%ld" ) % ( ( long )genQueryInp ) );
        std::string out_string = str( boost::format( "%ld" ) % ( ( long )genQueryOut ) );
        std::string status_string = str( boost::format( "%d" ) % ( ( long )status ) );
        args[0] = in_string.c_str();
        args[1] = out_string.c_str();
        args[2] = status_string.c_str();
        argc = 3;
        i =  applyRuleArg( "acPostProcForGenQuery", args, argc, &rei2, NO_SAVE_REI );
        if ( i < 0 ) {
            rodsLog( LOG_ERROR,
                     "rsGenQuery:acPostProcForGenQuery error,stat=%d", i );
            if ( i != NO_MICROSERVICE_FOUND_ERR ) {
                return i;
            }
        }
    }
    /**  June 1 2009 for pre-post processing rule hooks **/

    if ( status < 0 ) {
        clearGenQueryOut( *genQueryOut );
        free( *genQueryOut );
        *genQueryOut = NULL;
        if ( status != CAT_NO_ROWS_FOUND ) {
            rodsLog( LOG_NOTICE,
                     "_rsGenQuery: genQuery status = %d", status );
        }
        return status;
    }
    return status;
}
#endif
<commit_msg>[#1472] Added some genQueryInp/Out massaging to rsGenQuery for backward compatibility<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/

/* See genQuery.h for a description of this API call.*/

#include "reFuncDefs.hpp"
#include "genQuery.hpp"
#include "icatHighLevelRoutines.hpp"
#include "miscUtil.hpp"
#include "cache.hpp"
#include "rsGlobalExtern.hpp"
#include "irods_server_properties.hpp"

#include "boost/format.hpp"
#include <string>

static
irods::error strip_new_query_terms(
    genQueryInp_t* _inp ) {
    // =-=-=-=-=-=-=-
    // cache pointers to the incoming inxIvalPair
    inxIvalPair_t tmp;
    tmp.len   = _inp->selectInp.len;
    tmp.inx   = _inp->selectInp.inx;
    tmp.value = _inp->selectInp.value;

    // =-=-=-=-=-=-=-
    // zero out the selectInp to copy
    // fresh community indices and values
    bzero( &_inp->selectInp, sizeof( _inp->selectInp ) );

    // =-=-=-=-=-=-=-
    // iterate over the tmp and only copy community values
    for ( int i = 0; i < tmp.len; ++i ) {
        if ( tmp.inx[ i ] == COL_R_RESC_CHILDREN ||
                tmp.inx[ i ] == COL_R_RESC_CONTEXT  ||
                tmp.inx[ i ] == COL_R_RESC_PARENT   ||
                tmp.inx[ i ] == COL_R_RESC_OBJCOUNT ||
                tmp.inx[ i ] == COL_D_RESC_HIER ) {
            continue;
        }
        else {
            addInxIval( &_inp->selectInp, tmp.inx[ i ], tmp.value[ i ] );
        }

    } // for i

    return SUCCESS();

} // strip_new_query_terms

static
irods::error strip_resc_grp_name_from_query_inp(genQueryInp_t* _inp, int& _pos) {

	const int COL_D_RESC_GROUP_NAME  = 408;

	// sanity check
	if (!_inp) {
		return CODE(SYS_INTERNAL_NULL_INPUT_ERR);
	}

    // =-=-=-=-=-=-=-
    // cache pointers to the incoming inxIvalPair
    inxIvalPair_t tmp;
    tmp.len   = _inp->selectInp.len;
    tmp.inx   = _inp->selectInp.inx;
    tmp.value = _inp->selectInp.value;

    // =-=-=-=-=-=-=-
    // zero out the selectInp to copy
    // fresh indices and values
    bzero(&_inp->selectInp, sizeof(_inp->selectInp));

    // =-=-=-=-=-=-=-
    // iterate over tmp and replace resource group with resource name
    for (int i = 0; i<tmp.len; ++i) {
        if (tmp.inx[i] == COL_D_RESC_GROUP_NAME) {
        	addInxIval(&_inp->selectInp, COL_D_RESC_NAME, tmp.value[i]);
        	_pos = i;
        }
        else {
            addInxIval(&_inp->selectInp, tmp.inx[i], tmp.value[i]);
        }
    } // for i

    // cleanup
    if (tmp.inx) free(tmp.inx);
    if (tmp.value) free(tmp.value);

    return SUCCESS();

} // strip_resc_grp_name_from_query_inp

static
irods::error add_resc_grp_name_to_query_out(genQueryOut_t *_out, int& _pos) {

	const int COL_D_RESC_GROUP_NAME  = 408;

	// =-=-=-=-=-=-=-
	// Sanity checks
	if (!_out) {
		return CODE(SYS_INTERNAL_NULL_INPUT_ERR);
	}

	if (_pos < 0 || _pos > MAX_SQL_ATTR-1) {
		return CODE(SYS_INVALID_INPUT_PARAM);
	}

	sqlResult_t *sqlResult = &_out->sqlResult[_pos];
	if (!sqlResult || sqlResult->attriInx != COL_D_RESC_NAME) {
		return CODE(SYS_INTERNAL_ERR);
	}

	// =-=-=-=-=-=-=-
	// Swap attribute indices back
	sqlResult->attriInx = COL_D_RESC_GROUP_NAME;

    return SUCCESS();

} // add_resc_grp_name_to_query_out

static
irods::error proc_query_terms_for_community_server(
    const std::string& _zone_hint,
    genQueryInp_t*     _inp ) {
    bool        done     = false;
    zoneInfo_t* tmp_zone = ZoneInfoHead;
    // =-=-=-=-=-=-=-
    // if the zone hint starts with a / we
    // will need to pull out just the zone
    std::string zone_hint = _zone_hint;
    if ( _zone_hint[0] == '/' ) {
        size_t pos = _zone_hint.find( "/", 1 );
        if ( std::string::npos != pos ) {
            zone_hint = _zone_hint.substr( 1, pos - 1 );
        }
        else {
            zone_hint = _zone_hint.substr( 1 );
        }

    }
    else {
        return SUCCESS();
    }

    // =-=-=-=-=-=-=-
    // grind through the zones and find the match to the kw
    while ( !done && tmp_zone ) {
        if ( zone_hint == tmp_zone->zoneName               &&
                tmp_zone->masterServerHost->conn              &&
                tmp_zone->masterServerHost->conn->svrVersion &&
                tmp_zone->masterServerHost->conn->svrVersion->cookie < 301 ) {
            return strip_new_query_terms( _inp );

        }
        else {
            tmp_zone = tmp_zone->next;

        }
    }

    return SUCCESS();

} // proc_query_terms_for_community_server

/* can be used for debug: */
/* extern int printGenQI( genQueryInp_t *genQueryInp); */
;
int
rsGenQuery( rsComm_t *rsComm, genQueryInp_t *genQueryInp,
            genQueryOut_t **genQueryOut ) {
    rodsServerHost_t *rodsServerHost;
    int status;
    char *zoneHint;
    zoneHint = getZoneHintForGenQuery( genQueryInp );

    std::string zone_hint_str;
    if ( zoneHint ) {
        zone_hint_str = zoneHint;
    }

    status = getAndConnRcatHost( rsComm, SLAVE_RCAT, ( const char* )zoneHint,
                                 &rodsServerHost );

    if ( status < 0 ) {
        return status;
    }

    // =-=-=-=-=-=-=-
    // handle connections with community iRODS
    if ( !zone_hint_str.empty() ) {
        irods::error ret = proc_query_terms_for_community_server( zone_hint_str, genQueryInp );
        if ( !ret.ok() ) {
            irods::log( PASS( ret ) );
        }
    }

    if ( rodsServerHost->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsGenQuery( rsComm, genQueryInp, genQueryOut );
#else
        rodsLog( LOG_NOTICE,
                 "rsGenQuery error. RCAT is not configured on this host" );
        return SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        // =-=-=-=-=-=-=-
        // strip disable strict acl flag if the agent conn flag is missing
        char* dis_kw = getValByKey( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );
        if ( dis_kw ) {
            irods::server_properties& props = irods::server_properties::getInstance();
            props.capture_if_needed();

            std::string svr_sid;
            irods::error err = props.get_property< std::string >( irods::AGENT_CONN_KW, svr_sid );
            if ( !err.ok() ) {
                rmKeyVal( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );

            }

        } // if dis_kw

        status = rcGenQuery( rodsServerHost->conn,
                             genQueryInp, genQueryOut );
    }
    if ( status < 0  && status != CAT_NO_ROWS_FOUND ) {
        std::string prefix = ( rodsServerHost->localFlag == LOCAL_HOST ) ? "_rs" : "rc";
        rodsLog( LOG_NOTICE,
                 "rsGenQuery: %sGenQuery failed, status = %d", prefix.c_str(), status );
    }
    return status;
}

#ifdef RODS_CAT
int
_rsGenQuery( rsComm_t *rsComm, genQueryInp_t *genQueryInp,
             genQueryOut_t **genQueryOut ) {
    int status;
    int resc_grp_attr_pos = -1;

    static int ruleExecuted = 0;
    ruleExecInfo_t rei;

    static int PrePostProcForGenQueryFlag = -2;
    int i, argc;
    ruleExecInfo_t rei2;
    const char *args[MAX_NUM_OF_ARGS_IN_ACTION];

    // =-=-=-=-=-=-=-
    // handle queries from older clients
    std::string client_rel_version = rsComm->cliVersion.relVersion;
    std::string local_rel_version = RODS_REL_VERSION;
    if (client_rel_version != local_rel_version) {	// skip if version strings match
    	irods::error err = strip_resc_grp_name_from_query_inp(genQueryInp, resc_grp_attr_pos);
        if (!err.ok()) {
            irods::log(PASS(err));
        }
    }

    if ( PrePostProcForGenQueryFlag < 0 ) {
        if ( getenv( "PREPOSTPROCFORGENQUERYFLAG" ) != NULL ) {
            PrePostProcForGenQueryFlag = 1;
        }
        else {
            PrePostProcForGenQueryFlag = 0;
        }
    }

    memset( ( char* )&rei2, 0, sizeof( ruleExecInfo_t ) );
    rei2.rsComm = rsComm;
    if ( rsComm != NULL ) {
        rei2.uoic = &rsComm->clientUser;
        rei2.uoip = &rsComm->proxyUser;
    }

    /*  printGenQI(genQueryInp);  for debug */

    *genQueryOut = ( genQueryOut_t* )malloc( sizeof( genQueryOut_t ) );
    memset( ( char * )*genQueryOut, 0, sizeof( genQueryOut_t ) );

    if ( ruleExecuted == 0 ) {
        memset( ( char* )&rei, 0, sizeof( rei ) );
        rei.rsComm = rsComm;
        if ( rsComm != NULL ) {
            /* Include the user info for possible use by the rule.  Note
            that when this is called (as the agent is initializing),
            this user info is not confirmed yet.  For password
            authentication though, the agent will soon exit if this
            is not valid.  But for GSI, the user information may not
            be present and/or may be changed when the authentication
            completes, so it may not be safe to use this in a GSI
            enabled environment.  This addition of user information
            was requested by ARCS/IVEC (Sean Fleming) to avoid a
            local patch.
            */
            rei.uoic = &rsComm->clientUser;
            rei.uoip = &rsComm->proxyUser;
        }

        if ( getRuleEngineStatus() == UNINITIALIZED ) {
            /* Skip the call to run acAclPolicy if the Rule Engine
               hasn't been initialized yet, which happens for a couple
               initial queries made by the agent when starting up.  The
               new RE logs these types of errors and so this avoids that.
            */
            status = -1;
        }
        else {
            status = applyRule( "acAclPolicy", NULL, &rei, NO_SAVE_REI );
        }
        if ( status == 0 ) {
            ruleExecuted = 1; /* No need to retry next time since it
                             succeeded.  Since this is called at
                             startup, the Rule Engine may not be
                             initialized yet, in which case the
                             default setting is fine and we should
                             retry next time. */
        }
    }

    // =-=-=-=-=-=-=-
    // verify that we are running a query for another agent connection
    irods::server_properties& props = irods::server_properties::getInstance();
    props.capture_if_needed();

    std::string svr_sid;
    irods::error err = props.get_property< std::string >( irods::AGENT_CONN_KW, svr_sid );
    bool agent_conn_flg = err.ok();

    // =-=-=-=-=-=-=-
    // detect if a request for disable of strict acls is made
    int acl_val = -1;
    char* dis_kw = getValByKey( &genQueryInp->condInput, DISABLE_STRICT_ACL_KW );
    if ( agent_conn_flg && dis_kw ) {
        acl_val = 0;
    }

    // =-=-=-=-=-=-=-
    // cache the old acl value for reuse later if necessary
    int old_acl_val =  chlGenQueryAccessControlSetup(
                           rsComm->clientUser.userName,
                           rsComm->clientUser.rodsZone,
                           rsComm->clientAddr,
                           rsComm->clientUser.authInfo.authFlag,
                           acl_val );

    if ( PrePostProcForGenQueryFlag == 1 ) {
        std::string arg = str( boost::format( "%ld" ) % ( ( long )genQueryInp ) );
        args[0] = arg.c_str();
        argc = 1;
        i =  applyRuleArg( "acPreProcForGenQuery", args, argc, &rei2, NO_SAVE_REI );
        if ( i < 0 ) {
            rodsLog( LOG_ERROR,
                     "rsGenQuery:acPreProcForGenQuery error,stat=%d", i );
            if ( i != NO_MICROSERVICE_FOUND_ERR ) {
                return i;
            }
        }
    }
    /**  June 1 2009 for pre-post processing rule hooks **/

    status = chlGenQuery( *genQueryInp, *genQueryOut );

    // =-=-=-=-=-=-=-
    // if a disable was requested, repave with old value immediately
    if ( agent_conn_flg && dis_kw ) {
        chlGenQueryAccessControlSetup(
            rsComm->clientUser.userName,
            rsComm->clientUser.rodsZone,
            rsComm->clientAddr,
            rsComm->clientUser.authInfo.authFlag,
            old_acl_val );
    }

    /**  June 1 2009 for pre-post processing rule hooks **/
    if ( PrePostProcForGenQueryFlag == 1 ) {
        std::string in_string = str( boost::format( "%ld" ) % ( ( long )genQueryInp ) );
        std::string out_string = str( boost::format( "%ld" ) % ( ( long )genQueryOut ) );
        std::string status_string = str( boost::format( "%d" ) % ( ( long )status ) );
        args[0] = in_string.c_str();
        args[1] = out_string.c_str();
        args[2] = status_string.c_str();
        argc = 3;
        i =  applyRuleArg( "acPostProcForGenQuery", args, argc, &rei2, NO_SAVE_REI );
        if ( i < 0 ) {
            rodsLog( LOG_ERROR,
                     "rsGenQuery:acPostProcForGenQuery error,stat=%d", i );
            if ( i != NO_MICROSERVICE_FOUND_ERR ) {
                return i;
            }
        }
    }
    /**  June 1 2009 for pre-post processing rule hooks **/

    // =-=-=-=-=-=-=-
    // handle queries from older clients
    if (status >= 0 && resc_grp_attr_pos >= 0) {
    	irods::error err = add_resc_grp_name_to_query_out(*genQueryOut, resc_grp_attr_pos);
        if (!err.ok()) {
            irods::log(PASS(err));
        }
    }

    if ( status < 0 ) {
        clearGenQueryOut( *genQueryOut );
        free( *genQueryOut );
        *genQueryOut = NULL;
        if ( status != CAT_NO_ROWS_FOUND ) {
            rodsLog( LOG_NOTICE,
                     "_rsGenQuery: genQuery status = %d", status );
        }
        return status;
    }
    return status;
}
#endif
<|endoftext|>