text:
#include "SpatiaLiteCache.h"
#include "FlashMemoryCache.h"
#include "ObservationMemoryCache.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/make_shared.hpp>
#include <macgyver/StringConversion.h>
#include <spine/Convenience.h>
#include <atomic>

namespace ts = SmartMet::Spine::TimeSeries;

namespace SmartMet
{
namespace Engine
{
namespace Observation
{
namespace
{
// Round down to HH:MM:00. Deleting an entire hour at once takes too long, and causes a major
// increase in response times. This should perhaps be made configurable.

boost::posix_time::ptime round_down_to_cache_clean_interval(const boost::posix_time::ptime &t)
{
  auto secs = (t.time_of_day().total_seconds() / 60) * 60;
  return boost::posix_time::ptime(t.date(), boost::posix_time::seconds(secs));
}

}  // namespace

void SpatiaLiteCache::initializeConnectionPool()
{
  try
  {
    // Check if already initialized (one cache can be shared by multiple database drivers)
    if (itsConnectionPool)
    {
      // Cache already initialized
      return;
    }

    logMessage("[Observation Engine] Initializing SpatiaLite cache connection pool...",
               itsParameters.quiet);

    itsConnectionPool.reset(new SpatiaLiteConnectionPool(itsParameters));

    // Ensure that necessary tables exists:
    // 1) stations
    // 2) locations
    // 3) observation_data
    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    const std::set<std::string> &cacheTables = itsCacheInfo.tables;

    db->createTables(cacheTables);

    // Observation data
    if (cacheTables.find(OBSERVATION_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestObservationTime();
      auto end = db->getLatestObservationTime();
      itsTimeIntervalStart = start;
      itsTimeIntervalEnd = end;
    }

    // WeatherDataQC
    if (cacheTables.find(WEATHER_DATA_QC_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestWeatherDataQCTime();
      auto end = db->getLatestWeatherDataQCTime();
      itsWeatherDataQCTimeIntervalStart = start;
      itsWeatherDataQCTimeIntervalEnd = end;
    }

    // Flash
    if (cacheTables.find(FLASH_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestFlashTime();
      auto end = db->getLatestFlashTime();
      itsFlashTimeIntervalStart = start;
      itsFlashTimeIntervalEnd = end;
    }

    // Road cloud
    if (cacheTables.find(ROADCLOUD_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestRoadCloudDataTime();
      auto end = db->getLatestRoadCloudDataTime();
      itsRoadCloudTimeIntervalStart = start;
      itsRoadCloudTimeIntervalEnd = end;
    }

    // NetAtmo
    if (cacheTables.find(NETATMO_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestNetAtmoDataTime();
      auto end = db->getLatestNetAtmoDataTime();
      itsNetAtmoTimeIntervalStart = start;
      itsNetAtmoTimeIntervalEnd = end;
    }

    // BKHydrometa
    if (cacheTables.find(BK_HYDROMETA_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestBKHydrometaDataTime();
      auto end = db->getLatestBKHydrometaDataTime();
      itsBKHydrometaTimeIntervalStart = start;
      itsBKHydrometaTimeIntervalEnd = end;
    }

    // FmiIoT
    if (cacheTables.find(FMI_IOT_DATA_TABLE) != cacheTables.end())
    {
      auto start = db->getOldestFmiIoTDataTime();
      auto end = db->getLatestFmiIoTDataTime();
      itsFmiIoTTimeIntervalStart = start;
      itsFmiIoTTimeIntervalEnd = end;
    }

    logMessage("[Observation Engine] SpatiaLite connection pool ready.", itsParameters.quiet);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Initializing connection pool failed!")
        .addParameter("filename", itsParameters.cacheFile);
  }
}  // namespace Observation

void SpatiaLiteCache::initializeCaches(int /* finCacheDuration */,
                                       int finMemoryCacheDuration,
                                       int /* extCacheDuration */,
                                       int /* flashCacheDuration */,
                                       int flashMemoryCacheDuration)
{
  try
  {
    auto now = boost::posix_time::second_clock::universal_time();

    const std::set<std::string> &cacheTables = itsCacheInfo.tables;

    if (cacheTables.find(FLASH_DATA_TABLE) != cacheTables.end() && flashMemoryCacheDuration > 0)
    {
      logMessage("[Observation Engine] Initializing SpatiaLite flash memory cache",
                 itsParameters.quiet);
      itsFlashMemoryCache.reset(new FlashMemoryCache);
      auto timetokeep_memory = boost::posix_time::hours(flashMemoryCacheDuration);
      auto flashdata =
          itsConnectionPool->getConnection()->readFlashCacheData(now - timetokeep_memory);
      itsFlashMemoryCache->fill(flashdata);
    }
    if (cacheTables.find(OBSERVATION_DATA_TABLE) != cacheTables.end() && finMemoryCacheDuration > 0)
    {
      logMessage("[Observation Engine] Initializing SpatiaLite observation memory cache",
                 itsParameters.quiet);
      itsObservationMemoryCache.reset(new ObservationMemoryCache);
      auto timetokeep_memory = boost::posix_time::hours(finMemoryCacheDuration);
      itsConnectionPool->getConnection()->initObservationMemoryCache(now - timetokeep_memory,
                                                                     itsObservationMemoryCache);
    }

    logMessage("[Observation Engine] SpatiaLite memory cache ready.", itsParameters.quiet);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cache initialization failed!")
        .addParameter("filename", itsParameters.cacheFile);
  }
}

ts::TimeSeriesVectorPtr SpatiaLiteCache::valuesFromCache(Settings &settings)
{
  try
  {
    if (settings.stationtype == ROADCLOUD_PRODUCER)
      return roadCloudValuesFromSpatiaLite(settings);

    if (settings.stationtype == NETATMO_PRODUCER)
      return netAtmoValuesFromSpatiaLite(settings);

    if (settings.stationtype == BK_HYDROMETA_PRODUCER)
      return bkHydrometaValuesFromSpatiaLite(settings);

    if (settings.stationtype == FMI_IOT_PRODUCER)
      return fmiIoTValuesFromSpatiaLite(settings);

    if (settings.stationtype == "flash")
      return flashValuesFromSpatiaLite(settings);

    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    auto sinfo = itsParameters.stationInfo->load();

    SmartMet::Spine::Stations stations = sinfo->findFmisidStations(settings.taggedFMISIDs);
    stations = removeDuplicateStations(stations);

    // Get data if we have stations
    if (!stations.empty())
    {
      std::shared_ptr<CommonDatabaseFunctions> db = itsConnectionPool->getConnection();
      db->setDebug(settings.debug_options);
      db->setAdditionalTimestepOption(AdditionalTimestepOption::JustRequestedTimesteps);

      if ((settings.stationtype == "road" || settings.stationtype == "foreign") &&
          timeIntervalWeatherDataQCIsCached(settings.starttime, settings.endtime))
      {
		itsCacheStatistics.at(WEATHER_DATA_QC_TABLE).hit();
        ret = db->getWeatherDataQCData(stations, settings, *sinfo, itsTimeZones);
      }
      else
      {
        bool use_memory_cache = false;
        if (itsObservationMemoryCache)
        {
          // We know that spatialite cache hits will include memory cache hits, but do not
          // bother to substract the memory cache hits from spatialite hits

          auto cache_start_time = itsObservationMemoryCache->getStartTime();
          use_memory_cache =
              (!cache_start_time.is_not_a_date_time() && cache_start_time <= settings.starttime);
          if (use_memory_cache)
            itsCacheStatistics.at("observation_memory").hit();
          else
            itsCacheStatistics.at("observation_memory").miss();
        }

        ret = db->getObservationData(
            stations, settings, *sinfo, itsTimeZones, itsObservationMemoryCache);
      }
    }

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(
        BCP, "Getting values from cache for stationtype '" + settings.stationtype + "' failed!");
  }
}

ts::TimeSeriesVectorPtr SpatiaLiteCache::valuesFromCache(
    Settings &settings, const Spine::TimeSeriesGeneratorOptions &timeSeriesOptions)
{
  try
  {
    if (settings.stationtype == ROADCLOUD_PRODUCER)
      return roadCloudValuesFromSpatiaLite(settings);

    if (settings.stationtype == NETATMO_PRODUCER)
      return netAtmoValuesFromSpatiaLite(settings);

    if (settings.stationtype == BK_HYDROMETA_PRODUCER)
      return bkHydrometaValuesFromSpatiaLite(settings);

    if (settings.stationtype == FMI_IOT_PRODUCER)
      return fmiIoTValuesFromSpatiaLite(settings);

    if (settings.stationtype == "flash")
      return flashValuesFromSpatiaLite(settings);

    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    auto sinfo = itsParameters.stationInfo->load();

    SmartMet::Spine::Stations stations = sinfo->findFmisidStations(settings.taggedFMISIDs);
    stations = removeDuplicateStations(stations);

    // Get data if we have stations
    if (!stations.empty())
    {
      std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
      db->setDebug(settings.debug_options);
      db->setAdditionalTimestepOption(AdditionalTimestepOption::RequestedAndDataTimesteps);

      if ((settings.stationtype == "road" || settings.stationtype == "foreign") &&
          timeIntervalWeatherDataQCIsCached(settings.starttime, settings.endtime))
      {
		itsCacheStatistics.at(WEATHER_DATA_QC_TABLE).hit();
        ret = db->getWeatherDataQCData(stations, settings, *sinfo, timeSeriesOptions, itsTimeZones);
      }
      else
      {
        bool use_memory_cache = false;
        if (itsObservationMemoryCache)
        {
          // We know that spatialite cache hits will include memory cache hits, but do not
          // bother to substract the memory cache hits from spatialite hits

          auto cache_start_time = itsObservationMemoryCache->getStartTime();
          use_memory_cache =
              (!cache_start_time.is_not_a_date_time() && cache_start_time <= settings.starttime);

          if (use_memory_cache)
            itsCacheStatistics.at("observation_memory").hit();
          else
            itsCacheStatistics.at("observation_memory").miss();
        }

        ret = db->getObservationData(
            stations, settings, *sinfo, timeSeriesOptions, itsTimeZones, itsObservationMemoryCache);
      }
    }

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(
        BCP, "Getting values from cache for stationtype '" + settings.stationtype + "' failed!");
  }
}

ts::TimeSeriesVectorPtr SpatiaLiteCache::flashValuesFromSpatiaLite(Settings &settings) const
{
  try
  {
    // Use memory cache if possible. t is not set if the cache is not ready yet
    if (itsFlashMemoryCache)
    {
      auto t = itsFlashMemoryCache->getStartTime();

      if (!t.is_not_a_date_time() && settings.starttime >= t)
      {
        itsCacheStatistics.at("flash_memory").hit();
        return itsFlashMemoryCache->getData(settings, itsParameters.parameterMap, itsTimeZones);
      }
      itsCacheStatistics.at("flash_memory").miss();
    }

    // Must use disk cache instead
    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    db->setDebug(settings.debug_options);

    return db->getFlashData(settings, itsTimeZones);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting flash values from cache failed!");
  }
}

bool SpatiaLiteCache::timeIntervalIsCached(const boost::posix_time::ptime &starttime,
                                           const boost::posix_time::ptime & /* endtime */) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(OBSERVATION_DATA_TABLE);

    Spine::ReadLock lock(itsTimeIntervalMutex);

    if (itsTimeIntervalStart.is_not_a_date_time() || itsTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if time interval is cached failed!");
  }
}

bool SpatiaLiteCache::flashIntervalIsCached(const boost::posix_time::ptime &starttime,
                                            const boost::posix_time::ptime & /* endtime */) const
{
  try
  {
    // No need to check memory cache here, it is always supposed to be shorted than the disk cache

    auto &stat = itsCacheStatistics.at(FLASH_DATA_TABLE);

    Spine::ReadLock lock(itsFlashTimeIntervalMutex);

    if (itsFlashTimeIntervalStart.is_not_a_date_time() ||
        itsFlashTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsFlashTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if flash interval is cached failed!");
  }
}

bool SpatiaLiteCache::timeIntervalWeatherDataQCIsCached(
    const boost::posix_time::ptime &starttime, const boost::posix_time::ptime & /* endtime */) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(WEATHER_DATA_QC_TABLE);

    Spine::ReadLock lock(itsWeatherDataQCTimeIntervalMutex);
    if (itsWeatherDataQCTimeIntervalStart.is_not_a_date_time() ||
        itsWeatherDataQCTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsWeatherDataQCTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if weather data QC is cached failed!");
  }
}

bool SpatiaLiteCache::dataAvailableInCache(const Settings &settings) const
{
  try
  {
    // If stationtype is cached and if we have requested time interval in
    // SpatiaLite, get all data from there
    if (settings.useCommonQueryMethod)
      return timeIntervalIsCached(settings.starttime, settings.endtime);

    const auto &s = settings.stationtype;

    if (s == "road" || s == "foreign" || s == "observations_fmi_extaws")
      return timeIntervalWeatherDataQCIsCached(settings.starttime, settings.endtime);

    if (s == "flash")
      return flashIntervalIsCached(settings.starttime, settings.endtime);

    if (s == ROADCLOUD_PRODUCER)
      return roadCloudIntervalIsCached(settings.starttime, settings.endtime);

    if (s == NETATMO_PRODUCER)
      return netAtmoIntervalIsCached(settings.starttime, settings.endtime);

    if (s == BK_HYDROMETA_PRODUCER)
      return bkHydrometaIntervalIsCached(settings.starttime, settings.endtime);

    if (s == FMI_IOT_PRODUCER)
      return fmiIoTIntervalIsCached(settings.starttime, settings.endtime);

    // Either the stationtype is not cached or the requested time interval is
    // not cached
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if data is available in cache failed!");
  }
}

FlashCounts SpatiaLiteCache::getFlashCount(const boost::posix_time::ptime &starttime,
                                           const boost::posix_time::ptime &endtime,
                                           const Spine::TaggedLocationList &locations) const
{
  try
  {
    // Use memory cache if possible. t is not set if the cache is not ready yet
    if (itsFlashMemoryCache)
    {
      auto t = itsFlashMemoryCache->getStartTime();

      if (!t.is_not_a_date_time() && starttime >= t)
      {
        itsCacheStatistics.at("flash_memory").hit();
        return itsFlashMemoryCache->getFlashCount(starttime, endtime, locations);
      }
      itsCacheStatistics.at("flash_memory").miss();
    }

    // Must use disk cache instead
    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
	db->setDebug(false);

    return db->getFlashCount(starttime, endtime, locations);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting flash count from cache failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestFlashModifiedTime() const
{
  return itsConnectionPool->getConnection()->getLatestFlashModifiedTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestFlashTime() const
{
  return itsConnectionPool->getConnection()->getLatestFlashTime();
}

void SpatiaLiteCache::cleanMemoryDataCache(const boost::posix_time::ptime &newstarttime) const
{
  try
  {
    if (itsObservationMemoryCache)
      itsObservationMemoryCache->clean(newstarttime);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning of memory data cache failed!");
  }
}

std::size_t SpatiaLiteCache::fillFlashDataCache(const FlashDataItems &flashCacheData) const
{
  try
  {
    // Memory cache first
    if (itsFlashMemoryCache)
      itsFlashMemoryCache->fill(flashCacheData);

    // Then disk cache
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillFlashDataCache(flashCacheData, itsFlashInsertCache);

    // Update info on what is in the database
    auto start = conn->getOldestFlashTime();
    auto end = conn->getLatestFlashTime();
    Spine::WriteLock lock(itsFlashTimeIntervalMutex);
    itsFlashTimeIntervalStart = start;
    itsFlashTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling flash data cache failed!");
  }
}

void SpatiaLiteCache::cleanFlashDataCache(
    const boost::posix_time::time_duration &timetokeep,
    const boost::posix_time::time_duration &timetokeep_memory) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(FLASH_DATA_TABLE))
      return;

    auto now = boost::posix_time::second_clock::universal_time();

    // Clean memory cache first:

    if (itsFlashMemoryCache)
      itsFlashMemoryCache->clean(now - timetokeep_memory);

    // How old observations to keep in the disk cache:
    auto t = round_down_to_cache_clean_interval(now - timetokeep);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsFlashTimeIntervalMutex);
      itsFlashTimeIntervalStart = t;
    }
    conn->cleanFlashDataCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestFlashTime();
    auto end = conn->getLatestFlashTime();
    Spine::WriteLock lock(itsFlashTimeIntervalMutex);
    itsFlashTimeIntervalStart = start;
    itsFlashTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning flash data cache failed!");
  }
}

bool SpatiaLiteCache::roadCloudIntervalIsCached(const boost::posix_time::ptime &starttime,
                                                const boost::posix_time::ptime &) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(ROADCLOUD_DATA_TABLE);

    Spine::ReadLock lock(itsRoadCloudTimeIntervalMutex);
    if (itsRoadCloudTimeIntervalStart.is_not_a_date_time() &&
        itsRoadCloudTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsRoadCloudTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if road cloud interval is cached failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestRoadCloudDataTime() const
{
  return itsConnectionPool->getConnection()->getLatestRoadCloudDataTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestRoadCloudCreatedTime() const
{
  return itsConnectionPool->getConnection()->getLatestRoadCloudCreatedTime();
}

std::size_t SpatiaLiteCache::fillRoadCloudCache(
    const MobileExternalDataItems &mobileExternalCacheData) const
{
  try
  {
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillRoadCloudCache(mobileExternalCacheData, itsRoadCloudInsertCache);

    // Update what really now really is in the database
    auto start = conn->getOldestRoadCloudDataTime();
    auto end = conn->getLatestRoadCloudDataTime();
    Spine::WriteLock lock(itsRoadCloudTimeIntervalMutex);
    itsRoadCloudTimeIntervalStart = start;
    itsRoadCloudTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling road cloud cached failed!");
  }
}

void SpatiaLiteCache::cleanRoadCloudCache(const boost::posix_time::time_duration &timetokeep) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(ROADCLOUD_DATA_TABLE))
      return;

    boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time() - timetokeep;
    t = round_down_to_cache_clean_interval(t);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsRoadCloudTimeIntervalMutex);
      itsRoadCloudTimeIntervalStart = t;
    }
    conn->cleanRoadCloudCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestRoadCloudDataTime();
    auto end = conn->getLatestRoadCloudDataTime();
    Spine::WriteLock lock(itsRoadCloudTimeIntervalMutex);
    itsRoadCloudTimeIntervalStart = start;
    itsRoadCloudTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning road cloud cache failed!");
  }
}

Spine::TimeSeries::TimeSeriesVectorPtr SpatiaLiteCache::roadCloudValuesFromSpatiaLite(
    Settings &settings) const
{
  try
  {
    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    db->setDebug(settings.debug_options);
	itsCacheStatistics.at(ROADCLOUD_DATA_TABLE).hit();
    ret = db->getRoadCloudData(settings, itsTimeZones);

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting road cloud values from cache failed!");
  }
}

bool SpatiaLiteCache::netAtmoIntervalIsCached(const boost::posix_time::ptime &starttime,
                                              const boost::posix_time::ptime &) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(NETATMO_DATA_TABLE);
    Spine::ReadLock lock(itsNetAtmoTimeIntervalMutex);
    if (itsNetAtmoTimeIntervalStart.is_not_a_date_time() ||
        itsNetAtmoTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsNetAtmoTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if NetAtmo interval is cached failed!");
  }
}

std::size_t SpatiaLiteCache::fillNetAtmoCache(
    const MobileExternalDataItems &mobileExternalCacheData) const
{
  try
  {
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillNetAtmoCache(mobileExternalCacheData, itsNetAtmoInsertCache);

    // Update what really now really is in the database
    auto start = conn->getOldestNetAtmoDataTime();
    auto end = conn->getLatestNetAtmoDataTime();
    Spine::WriteLock lock(itsNetAtmoTimeIntervalMutex);
    itsNetAtmoTimeIntervalStart = start;
    itsNetAtmoTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling NetAtmo cache failed!");
  }
}

void SpatiaLiteCache::cleanNetAtmoCache(const boost::posix_time::time_duration &timetokeep) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(NETATMO_DATA_TABLE))
      return;

    boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time() - timetokeep;
    t = round_down_to_cache_clean_interval(t);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsNetAtmoTimeIntervalMutex);
      itsNetAtmoTimeIntervalStart = t;
    }
    conn->cleanNetAtmoCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestNetAtmoDataTime();
    auto end = conn->getLatestNetAtmoDataTime();
    Spine::WriteLock lock(itsNetAtmoTimeIntervalMutex);
    itsNetAtmoTimeIntervalStart = start;
    itsNetAtmoTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning NetAtmo cache failed!");
  }
}

Spine::TimeSeries::TimeSeriesVectorPtr SpatiaLiteCache::netAtmoValuesFromSpatiaLite(
    Settings &settings) const
{
  try
  {
    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    db->setDebug(settings.debug_options);
	itsCacheStatistics.at(NETATMO_DATA_TABLE).hit();
    ret = db->getNetAtmoData(settings, itsTimeZones);

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting NetAtmo values from cache failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestNetAtmoDataTime() const
{
  return itsConnectionPool->getConnection()->getLatestNetAtmoDataTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestNetAtmoCreatedTime() const
{
  return itsConnectionPool->getConnection()->getLatestNetAtmoCreatedTime();
}

bool SpatiaLiteCache::bkHydrometaIntervalIsCached(const boost::posix_time::ptime &starttime,
                                                  const boost::posix_time::ptime &) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(BK_HYDROMETA_DATA_TABLE);

    Spine::ReadLock lock(itsBKHydrometaTimeIntervalMutex);
    if (itsBKHydrometaTimeIntervalStart.is_not_a_date_time() ||
        itsBKHydrometaTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsBKHydrometaTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if BKHydrometa interval is cached failed!");
  }
}

std::size_t SpatiaLiteCache::fillBKHydrometaCache(
    const MobileExternalDataItems &mobileExternalCacheData) const
{
  try
  {
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillBKHydrometaCache(mobileExternalCacheData, itsBKHydrometaInsertCache);

    // Update what really now really is in the database
    auto start = conn->getOldestBKHydrometaDataTime();
    auto end = conn->getLatestBKHydrometaDataTime();
    Spine::WriteLock lock(itsBKHydrometaTimeIntervalMutex);
    itsBKHydrometaTimeIntervalStart = start;
    itsBKHydrometaTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling BKHydrometa cache failed!");
  }
}

void SpatiaLiteCache::cleanBKHydrometaCache(
    const boost::posix_time::time_duration &timetokeep) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(BK_HYDROMETA_DATA_TABLE))
      return;

    boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time() - timetokeep;
    t = round_down_to_cache_clean_interval(t);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsBKHydrometaTimeIntervalMutex);
      itsBKHydrometaTimeIntervalStart = t;
    }
    conn->cleanBKHydrometaCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestBKHydrometaDataTime();
    auto end = conn->getLatestBKHydrometaDataTime();
    Spine::WriteLock lock(itsBKHydrometaTimeIntervalMutex);
    itsBKHydrometaTimeIntervalStart = start;
    itsBKHydrometaTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning BKHydrometa cache failed!");
  }
}

Spine::TimeSeries::TimeSeriesVectorPtr SpatiaLiteCache::bkHydrometaValuesFromSpatiaLite(
    Settings &settings) const
{
  try
  {
    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    db->setDebug(settings.debug_options);
	itsCacheStatistics.at(BK_HYDROMETA_DATA_TABLE).hit();
    ret = db->getBKHydrometaData(settings, itsTimeZones);

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting BKHydrometa values from cache failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestBKHydrometaDataTime() const
{
  return itsConnectionPool->getConnection()->getLatestBKHydrometaDataTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestBKHydrometaCreatedTime() const
{
  return itsConnectionPool->getConnection()->getLatestBKHydrometaCreatedTime();
}

bool SpatiaLiteCache::fmiIoTIntervalIsCached(const boost::posix_time::ptime &starttime,
                                             const boost::posix_time::ptime &) const
{
  try
  {
    auto &stat = itsCacheStatistics.at(FMI_IOT_DATA_TABLE);

    Spine::ReadLock lock(itsFmiIoTTimeIntervalMutex);
    if (itsFmiIoTTimeIntervalStart.is_not_a_date_time() ||
        itsFmiIoTTimeIntervalEnd.is_not_a_date_time())
    {
      stat.miss();
      return false;
    }

    // We ignore end time intentionally
    if (starttime >= itsFmiIoTTimeIntervalStart)
    {
      stat.hit();
      return true;
    }
    stat.miss();
    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Checking if FmiIoT interval is cached failed!");
  }
}

std::size_t SpatiaLiteCache::fillFmiIoTCache(
    const MobileExternalDataItems &mobileExternalCacheData) const
{
  try
  {
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillFmiIoTCache(mobileExternalCacheData, itsFmiIoTInsertCache);

    // Update what really now really is in the database
    auto start = conn->getOldestFmiIoTDataTime();
    auto end = conn->getLatestFmiIoTDataTime();
    Spine::WriteLock lock(itsFmiIoTTimeIntervalMutex);
    itsFmiIoTTimeIntervalStart = start;
    itsFmiIoTTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling FmiIoT cache failed!");
  }
}

void SpatiaLiteCache::cleanFmiIoTCache(const boost::posix_time::time_duration &timetokeep) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(FMI_IOT_DATA_TABLE))
      return;

    boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time() - timetokeep;
    t = round_down_to_cache_clean_interval(t);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsFmiIoTTimeIntervalMutex);
      itsFmiIoTTimeIntervalStart = t;
    }
    conn->cleanFmiIoTCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestFmiIoTDataTime();
    auto end = conn->getLatestFmiIoTDataTime();
    Spine::WriteLock lock(itsFmiIoTTimeIntervalMutex);
    itsFmiIoTTimeIntervalStart = start;
    itsFmiIoTTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning FmiIoT cache failed!");
  }
}

Spine::TimeSeries::TimeSeriesVectorPtr SpatiaLiteCache::fmiIoTValuesFromSpatiaLite(
    Settings &settings) const
{
  try
  {
    ts::TimeSeriesVectorPtr ret(new ts::TimeSeriesVector);

    std::shared_ptr<SpatiaLite> db = itsConnectionPool->getConnection();
    db->setDebug(settings.debug_options);
	itsCacheStatistics.at(FMI_IOT_DATA_TABLE).hit();
    ret = db->getFmiIoTData(settings, itsTimeZones);

    return ret;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting FmiIoT values from cache failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestFmiIoTDataTime() const
{
  return itsConnectionPool->getConnection()->getLatestFmiIoTDataTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestFmiIoTCreatedTime() const
{
  return itsConnectionPool->getConnection()->getLatestFmiIoTCreatedTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestObservationModifiedTime() const
{
  return itsConnectionPool->getConnection()->getLatestObservationModifiedTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestObservationTime() const
{
  return itsConnectionPool->getConnection()->getLatestObservationTime();
}

std::size_t SpatiaLiteCache::fillDataCache(const DataItems &cacheData) const
{
  try
  {
    // Update memory cache first

    if (itsObservationMemoryCache)
      itsObservationMemoryCache->fill(cacheData);

    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillDataCache(cacheData, itsDataInsertCache);

    // Update what really now really is in the database
    auto start = conn->getOldestObservationTime();
    auto end = conn->getLatestObservationTime();
    Spine::WriteLock lock(itsTimeIntervalMutex);
    itsTimeIntervalStart = start;
    itsTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling data cache failed!");
  }
}

void SpatiaLiteCache::cleanDataCache(
    const boost::posix_time::time_duration &timetokeep,
    const boost::posix_time::time_duration &timetokeep_memory) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(OBSERVATION_DATA_TABLE))
      return;

    auto now = boost::posix_time::second_clock::universal_time();

    auto time1 = round_down_to_cache_clean_interval(now - timetokeep);
    auto time2 = round_down_to_cache_clean_interval(now - timetokeep_memory);

    cleanMemoryDataCache(time2);

    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsTimeIntervalMutex);
      itsTimeIntervalStart = time1;
    }
    auto conn = itsConnectionPool->getConnection();
    conn->cleanDataCache(time1);

    // Update what really remains in the database
    auto start = conn->getOldestObservationTime();
    auto end = conn->getLatestObservationTime();
    Spine::WriteLock lock(itsTimeIntervalMutex);
    itsTimeIntervalStart = start;
    itsTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning data cache failed!");
  }
}

boost::posix_time::ptime SpatiaLiteCache::getLatestWeatherDataQCTime() const
{
  return itsConnectionPool->getConnection()->getLatestWeatherDataQCTime();
}

boost::posix_time::ptime SpatiaLiteCache::getLatestWeatherDataQCModifiedTime() const
{
  return itsConnectionPool->getConnection()->getLatestWeatherDataQCModifiedTime();
}

std::size_t SpatiaLiteCache::fillWeatherDataQCCache(const WeatherDataQCItems &cacheData) const
{
  try
  {
    auto conn = itsConnectionPool->getConnection();
    auto sz = conn->fillWeatherDataQCCache(cacheData, itsWeatherQCInsertCache);
    // Update what really now really is in the database
    auto start = conn->getOldestWeatherDataQCTime();
    auto end = conn->getLatestWeatherDataQCTime();
    Spine::WriteLock lock(itsTimeIntervalMutex);
    itsWeatherDataQCTimeIntervalStart = start;
    itsWeatherDataQCTimeIntervalEnd = end;
    return sz;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Filling weather data QC cache failed!");
  }
}

void SpatiaLiteCache::cleanWeatherDataQCCache(
    const boost::posix_time::time_duration &timetokeep) const
{
  try
  {
    // Dont clean fake cache
    if (isFakeCache(WEATHER_DATA_QC_TABLE))
      return;

    boost::posix_time::ptime t = boost::posix_time::second_clock::universal_time() - timetokeep;
    t = round_down_to_cache_clean_interval(t);

    auto conn = itsConnectionPool->getConnection();
    {
      // We know the cache will not contain anything before this after the update
      Spine::WriteLock lock(itsWeatherDataQCTimeIntervalMutex);
      itsWeatherDataQCTimeIntervalStart = t;
    }
    conn->cleanWeatherDataQCCache(t);

    // Update what really remains in the database
    auto start = conn->getOldestWeatherDataQCTime();
    auto end = conn->getLatestWeatherDataQCTime();
    Spine::WriteLock lock(itsTimeIntervalMutex);
    itsWeatherDataQCTimeIntervalStart = start;
    itsWeatherDataQCTimeIntervalEnd = end;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Cleaning weather data QC cache failed!");
  }
}

void SpatiaLiteCache::shutdown()
{
  if (itsConnectionPool)
    itsConnectionPool->shutdown();
  itsConnectionPool = nullptr;
}

// This has been added for flash emulator
int SpatiaLiteCache::getMaxFlashId() const
{
  try
  {
    return itsConnectionPool->getConnection()->getMaxFlashId();
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Getting maximum flash id from cache failed!");
  }
}

SpatiaLiteCache::SpatiaLiteCache(const std::string &name,
                                 const EngineParametersPtr &p,
                                 const Spine::ConfigBase &cfg)
    : ObservationCache(p->databaseDriverInfo.getAggregateCacheInfo(name)), itsParameters(p)
{
  try
  {
    // Create cache statistics objecs for each table
    for (const auto &tablename : itsCacheInfo.tables)
    {
      itsCacheStatistics.insert(std::make_pair(tablename, Fmi::Cache::CacheStats()));

      if (tablename == OBSERVATION_DATA_TABLE)
      {
        itsCacheStatistics.insert(std::make_pair("observation_memory", Fmi::Cache::CacheStats()));
      }
      else if (tablename == FLASH_DATA_TABLE)
      {
        itsCacheStatistics.insert(std::make_pair("flash_memory", Fmi::Cache::CacheStats()));
      }
    }

    readConfig(cfg);

    // Verify multithreading is possible
    if (!sqlite3_threadsafe())
      throw Fmi::Exception(BCP, "Installed sqlite is not thread safe");
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Creating SpatiaLite cache failed!");
  }
}

void SpatiaLiteCache::readConfig(const Spine::ConfigBase & /* cfg */)
{
  try
  {
    itsParameters.connectionPoolSize = Fmi::stoi(itsCacheInfo.params.at("poolSize"));
    itsParameters.cacheFile = itsCacheInfo.params.at("spatialiteFile");
    itsParameters.maxInsertSize = Fmi::stoi(itsCacheInfo.params.at("maxInsertSize"));

    itsDataInsertCache.resize(Fmi::stoi(itsCacheInfo.params.at("dataInsertCacheSize")));
    itsWeatherQCInsertCache.resize(
        Fmi::stoi(itsCacheInfo.params.at("weatherDataQCInsertCacheSize")));
    itsFlashInsertCache.resize(Fmi::stoi(itsCacheInfo.params.at("flashInsertCacheSize")));
    itsRoadCloudInsertCache.resize(Fmi::stoi(itsCacheInfo.params.at("roadCloudInsertCacheSize")));
    itsNetAtmoInsertCache.resize(Fmi::stoi(itsCacheInfo.params.at("netAtmoInsertCacheSize")));
    itsFmiIoTInsertCache.resize(Fmi::stoi(itsCacheInfo.params.at("fmiIoTInsertCacheSize")));

    itsParameters.sqlite.cache_size = Fmi::stoi(itsCacheInfo.params.at("cache_size"));
    itsParameters.sqlite.threads = Fmi::stoi(itsCacheInfo.params.at("threads"));
    itsParameters.sqlite.timeout = Fmi::stoi(itsCacheInfo.params.at("timeout"));
    itsParameters.sqlite.shared_cache = (Fmi::stoi(itsCacheInfo.params.at("shared_cache")) == 1);
    itsParameters.sqlite.read_uncommitted =
        (Fmi::stoi(itsCacheInfo.params.at("read_uncommitted")) == 1);
    itsParameters.sqlite.synchronous = itsCacheInfo.params.at("synchronous");
    itsParameters.sqlite.journal_mode = itsCacheInfo.params.at("journal_mode");
    itsParameters.sqlite.temp_store = itsCacheInfo.params.at("temp_store");
    itsParameters.sqlite.auto_vacuum = itsCacheInfo.params.at("auto_vacuum");
    itsParameters.sqlite.mmap_size = Fmi::stoi(itsCacheInfo.params.at("mmap_size"));
    itsParameters.sqlite.wal_autocheckpoint =
        Fmi::stoi(itsCacheInfo.params.at("wal_autocheckpoint"));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Reading SpatiaLite settings from configuration file failed!");
  }
}

Fmi::Cache::CacheStatistics SpatiaLiteCache::getCacheStats() const
{
  return itsCacheStatistics;
}

SpatiaLiteCache::~SpatiaLiteCache()
{
  shutdown();
}

}  // namespace Observation
}  // namespace Engine
}  // namespace SmartMet

max_stars_repo_name: fmidev/smartmet-engine-observation

max_issues_repo_name: fmidev/smartmet-engine-observation

max_forks_repo_name: fmidev/smartmet-engine-observation


text:
// Boost.TypeErasure library
//
// Copyright 2012 Steven Watanabe
//
// Distributed under the Boost Software License Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// $Id$

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/mpl/vector.hpp>

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

using namespace boost::type_erasure;

BOOST_TYPE_ERASURE_MEMBER((ns)(ns2)(has_fun), fun, 0)

struct model {
    explicit model(int v) : val(v) {}
    int f1() { return val; }
    int f1(int i) { return val + i; }
    int val;
};

BOOST_TYPE_ERASURE_MEMBER((global_has_f1_0), f1, 0)

BOOST_AUTO_TEST_CASE(test_global_has_f1_0) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int()>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_0_ref) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int()>,
        copy_constructible<> > concept_type;
    model m(10);
    const any<concept_type, _self&> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_TYPE_ERASURE_MEMBER((ns1)(ns2)(ns_has_f1_0), f1, 0)

BOOST_AUTO_TEST_CASE(test_ns_has_f1_0) {
    typedef ::boost::mpl::vector<
        ns1::ns2::ns_has_f1_0<int()>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

struct model_const {
    explicit model_const(int v) : val(v) {}
    int f1() const { return val; }
    int f1(int i) const { return val + i; }
    int val;
};

BOOST_AUTO_TEST_CASE(test_global_has_f1_0_const) {
    typedef ::boost::mpl::vector<
        ns1::ns2::ns_has_f1_0<int(), const _self>,
        copy_constructible<> > concept_type;
    model_const m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_0_const_ref) {
    typedef ::boost::mpl::vector<
        ns1::ns2::ns_has_f1_0<int(), const _self>,
        copy_constructible<> > concept_type;
    model_const m(10);
    const any<concept_type, _self&> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_0_const_cref) {
    typedef ::boost::mpl::vector<
        ns1::ns2::ns_has_f1_0<int(), const _self>,
        copy_constructible<> > concept_type;
    model_const m(10);
    const any<concept_type, const _self&> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_0_void) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<void()>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    x.f1();
}

BOOST_TYPE_ERASURE_MEMBER((global_has_f1_1), f1, 1)

BOOST_AUTO_TEST_CASE(test_global_has_f1_overload) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int()>,
        global_has_f1_1<int(int)>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_overload_const) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int(), const _self>,
        global_has_f1_1<int(int), const _self>,
        copy_constructible<> > concept_type;
    model_const m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

struct model_overload_const_non_const {
    int f1() { return 1; }
    int f1() const { return 2; }
};

BOOST_AUTO_TEST_CASE(test_global_has_f1_overload_const_non_const) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int(), _self>,
        global_has_f1_0<int(), const _self>,
        copy_constructible<> > concept_type;
    model_overload_const_non_const m;
    any<concept_type> x1(m);
    BOOST_CHECK_EQUAL(x1.f1(), 1);
    const any<concept_type> x2(m);
    BOOST_CHECK_EQUAL(x2.f1(), 2);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_overload_const_non_const_ref) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int(), const _self>, // FIXME: This is order sensitive
        global_has_f1_0<int(), _self>,
        copy_constructible<> > concept_type;
    model_overload_const_non_const m;
    any<concept_type, _self&> x1(m);
    BOOST_CHECK_EQUAL(x1.f1(), 1);
    const any<concept_type, _self&> x2(m);
    BOOST_CHECK_EQUAL(x2.f1(), 1);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_overload_const_non_const_cref) {
    typedef ::boost::mpl::vector<
        global_has_f1_0<int(), _self>,
        global_has_f1_0<int(), const _self>,
        copy_constructible<> > concept_type;
    model_overload_const_non_const m;
    any<concept_type, const _self&> x1(m);
    BOOST_CHECK_EQUAL(x1.f1(), 2);
    const any<concept_type, const _self&> x2(m);
    BOOST_CHECK_EQUAL(x2.f1(), 2);
}

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

BOOST_AUTO_TEST_CASE(test_global_has_f1_rv) {
    typedef ::boost::mpl::vector<
        global_has_f1_1<int(int&&)>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

BOOST_AUTO_TEST_CASE(test_global_has_f1_rv_const) {
    typedef ::boost::mpl::vector<
        global_has_f1_1<int(int&&), const _self>,
        copy_constructible<> > concept_type;
    model_const m(10);
    const any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

#endif

#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \
    !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
    !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
    !defined(BOOST_NO_CXX11_DECLTYPE) && \
    !BOOST_WORKAROUND(BOOST_MSVC, == 1800)

namespace ns3 {
BOOST_TYPE_ERASURE_MEMBER(f1);
}

BOOST_AUTO_TEST_CASE(test_simple_member_0) {
    typedef ::boost::mpl::vector<
        ns3::has_f1<int()>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(), 10);
}

BOOST_AUTO_TEST_CASE(test_simple_member_1) {
    typedef ::boost::mpl::vector<
        ns3::has_f1<int(int)>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

namespace ns3 {
BOOST_TYPE_ERASURE_MEMBER(has_f1_ex, f1);
}

BOOST_AUTO_TEST_CASE(test_named_member_1) {
    typedef ::boost::mpl::vector<
        ns3::has_f1_ex<int(int)>,
        copy_constructible<> > concept_type;
    model m(10);
    any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

BOOST_AUTO_TEST_CASE(test_named_member_1_const) {
    typedef ::boost::mpl::vector<
        ns3::has_f1_ex<int(int) const>,
        copy_constructible<> > concept_type;
    model_const m(10);
    const any<concept_type> x(m);
    BOOST_CHECK_EQUAL(x.f1(5), 15);
}

#endif

ext: cpp


text:
// Autogenerated from KST: please remove this line if doing any edits by hand!

#include <boost/test/unit_test.hpp>
#include "enum_long_range_s.h"
#include <iostream>
#include <fstream>
#include <vector>

BOOST_AUTO_TEST_CASE(test_enum_long_range_s) {
    std::ifstream ifs("src/enum_long_range_s.bin", std::ifstream::binary);
    kaitai::kstream ks(&ifs);
    enum_long_range_s_t* r = new enum_long_range_s_t(&ks);

    BOOST_CHECK_EQUAL(r->f1(), enum_long_range_s_t::CONSTANTS_LONG_MIN);
    BOOST_CHECK_EQUAL(r->f2(), enum_long_range_s_t::CONSTANTS_INT_BELOW_MIN);
    BOOST_CHECK_EQUAL(r->f3(), enum_long_range_s_t::CONSTANTS_INT_MIN);
    BOOST_CHECK_EQUAL(r->f4(), enum_long_range_s_t::CONSTANTS_ZERO);
    BOOST_CHECK_EQUAL(r->f5(), enum_long_range_s_t::CONSTANTS_INT_MAX);
    BOOST_CHECK_EQUAL(r->f6(), enum_long_range_s_t::CONSTANTS_INT_OVER_MAX);
    BOOST_CHECK_EQUAL(r->f7(), enum_long_range_s_t::CONSTANTS_LONG_MAX);

    delete r;
}


text:
/*
@copyright Louis Dionne 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_TEST_LAWS_PRODUCT_HPP
#define BOOST_HANA_TEST_LAWS_PRODUCT_HPP

#include <boost/hana/assert.hpp>
#include <boost/hana/comparable.hpp>
#include <boost/hana/bool.hpp>
#include <boost/hana/core/models.hpp>
#include <boost/hana/core/operators.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/product.hpp>

#include <laws/base.hpp>

namespace boost { namespace hana { namespace test {
    template <typename P, typename = when<true>>
    struct TestProduct : TestProduct<P, laws> {
        using TestProduct<P, laws>::TestProduct;
    };

    template <typename P>
    struct TestProduct<P, laws> {
        static_assert(_models<Product, P>{}, "");

        template <typename Elements>
        TestProduct(Elements elements) {
            foreach2(elements, [](auto x, auto y) {
                BOOST_HANA_CHECK(hana::equal(
                    hana::first(hana::make<P>(x, y)),
                    x
                ));

                BOOST_HANA_CHECK(hana::equal(
                    hana::second(hana::make<P>(x, y)),
                    y
                ));
            });
        }
    };
}}} // end namespace boost::hana::test

#endif // !BOOST_HANA_TEST_LAWS_PRODUCT_HPP

ext: hpp

max_stars_repo_name: josephwinston/hana

max_issues_repo_name: josephwinston/hana

max_forks_repo_name: josephwinston/hana


text:
/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include <gtest/gtest.h>

#include <functional>
#include <iostream>

#include "DexLoader.h"
#include "InstructionLowering.h"
#include "tools/bytecode-debugger/InjectDebug.h"

#include <boost/filesystem.hpp>

/* Tests that the inject-debug program is able to run to completion and
 * output a new dex file. Tests are run on the output dex file to
 * ensure it is in the state that we want.
 */

class InjectDebugTest : public ::testing::Test {
 protected:
  InjectDebugTest() {}

  void SetUp() override {
    reset_redex();
    m_dex_path = std::getenv("dex");
    m_tmp_dir = make_tmp_dir();
    m_modified_dex_path = m_tmp_dir + "/classes.dex";

    std::cout << "(SetUp) Using dex file at " << m_dex_path << std::endl;
    std::cout << "(SetUp) Using temp directory at " << m_tmp_dir << std::endl;

    // Create new dex file with injected debug information
    InjectDebug inject_debug(m_tmp_dir, {m_dex_path});
    inject_debug.run();
  }

  std::string make_tmp_dir() {
    boost::filesystem::path dex_dir = boost::filesystem::temp_directory_path();
    dex_dir +=
        boost::filesystem::unique_path("/redex_inject_debug_test%%%%%%%%");
    boost::filesystem::create_directories(dex_dir);
    boost::filesystem::path meta_dir(dex_dir.string() + "/meta");
    boost::filesystem::create_directories(meta_dir);
    return dex_dir.string();
  }

  void reset_redex() {
    delete g_redex;
    g_redex = new RedexContext(true);
  }

  DexClasses load_classes(const std::string& path) {
    reset_redex();
    DexStore store("classes");
    store.add_classes(load_classes_from_dex(path.c_str(), /* balloon */ false));
    DexClasses classes = store.get_dexen()[0];
    return classes;
  }

  // Helper to reduce duplicate code - runs a given function to fetch
  // information from classes and then checks equality
  void test_dex_equality_helper(
      const std::function<std::vector<std::string>(DexClasses)>& get_info) {
    std::vector<std::string> original_names, modified_names;
    original_names = get_info(load_classes(m_dex_path));
    modified_names = get_info(load_classes(m_modified_dex_path));

    EXPECT_EQ(original_names.size(), modified_names.size());

    for (int i = 0; i < original_names.size(); ++i) {
      EXPECT_EQ(original_names[i], modified_names[i]);
    }
  }

  std::string m_dex_path, m_tmp_dir, m_modified_dex_path;
};

// Check that general class data is unmodified by comparing class names
TEST_F(InjectDebugTest, TestClasses) {
  test_dex_equality_helper(
      [](const DexClasses& classes) -> std::vector<std::string> {
        std::vector<std::string> class_names;
        for (DexClass* dex_class : classes) {
          class_names.push_back(dex_class->str());
        }
        return class_names;
      });
}

// Check that general method data is unmodified by comparing method names
TEST_F(InjectDebugTest, TestMethods) {
  test_dex_equality_helper(
      [](const DexClasses& classes) -> std::vector<std::string> {
        std::vector<std::string> method_names;
        for (DexClass* dex_class : classes) {
          for (DexMethod* dex_method : dex_class->get_dmethods())
            method_names.push_back(dex_method->str());
          for (DexMethod* dex_method : dex_class->get_vmethods())
            method_names.push_back(dex_method->str());
        }
        return method_names;
      });
}

// Check that general code data is unmodified by comparing instructions
TEST_F(InjectDebugTest, TestCodeItems) {
  test_dex_equality_helper([](DexClasses classes) -> std::vector<std::string> {
    std::vector<std::string> instructions;
    for (int i = 0; i < classes.size(); ++i) {
      for (DexMethod* dex_method : classes[i]->get_dmethods()) {
        for (DexInstruction* dex_instr :
             dex_method->get_dex_code()->get_instructions()) {
          instructions.push_back(show(dex_instr));
        }
      }
    }
    return instructions;
  });
}

max_stars_repo_name: penguin-wwy/redex

max_issues_repo_name: penguin-wwy/redex

max_forks_repo_name: penguin-wwy/redex


text:
#ifndef ALGEBRA_CRT_HPP
#define ALGEBRA_CRT_HPP
#include <NTL/ZZ.h>
#include <vector>
namespace MDL {
/// @brief Chinese Remainder Theorm
/// @param a. the remainders
/// @param p. the primes
/// @return x such that x = a[0] mod p[0]
///                     x = a[1] mod p[1] ....
template <typename T, typename R>
NTL::ZZ CRT(const std::vector<T> &a, const std::vector<R> &p);

template <>
NTL::ZZ CRT(const std::vector<long> &a, const std::vector<NTL::ZZ> &p);
} // namespace MDL
#endif // algebra//crt.hpp

max_stars_repo_name: fionser/MDLHElib

max_issues_repo_name: fionser/MDLHElib

max_forks_repo_name: fionser/MDLHElib


text:
/*******************************************************************************
*
*  Filename    : OptNamer.cc
*  Description : Implementations for OptNamer class
*  Author      : Yi-Mu "Enoch" Chen [ ensc@hep1.phys.ntu.edu.tw ]
*
*******************************************************************************/
#include "ManagerUtils/Common/interface/OptNamer.hpp"

#include <boost/exception/diagnostic_information.hpp>
#include <boost/lexical_cast.hpp>

#include <iostream>

using namespace std;
namespace pt  = boost::property_tree;
namespace opt = boost::program_options;

namespace mgr {
/*******************************************************************************
*   Constructor/destructor
*******************************************************************************/
OptNamer::OptNamer( const string& filename ) :
  _exttree( FromJsonFile(filename) )
{
  _optdesc.add_options()
    ( "help,h", "print help options and exit program" )
  ;
}

/******************************************************************************/

OptNamer::~OptNamer(){}

/*******************************************************************************
*  Loading functions
*******************************************************************************/
OptNamer& OptNamer::AddOptions( const opt::options_description& desc )
{
  Description().add( desc );
  return *this;
}

/******************************************************************************/

int
OptNamer::ParseOptions( int argc, char** argv )
{
  try {
    opt::store( opt::parse_command_line( argc, argv, Description() ), Args() );
    opt::notify( Args() );
  } catch( boost::exception& e ){
    cerr << "Error parsing command!" << endl;
    cerr << boost::diagnostic_information( e );
    cerr << Description() << endl;
    return PARSE_ERROR;
  }

  if( Args().count( "help" ) ){
    cerr << Description() << endl;
    return PARSE_HELP;
  }

  return PARSE_SUCESS;
}

/*******************************************************************************
*   Input access functions
*******************************************************************************/
bool
OptNamer::CheckInput( const std::string& opt ) const
{
  return Args().count( opt );
}

}/* mgr */

ext: cc

max_stars_repo_name: NTUHEP-Tstar/ManagerUtils

max_issues_repo_name: NTUHEP-Tstar/ManagerUtils

max_forks_repo_name: NTUHEP-Tstar/ManagerUtils


text:
//
//  Copyright (C) 2021 Danny Havenith
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
#include "tool_implementation.hpp"

#include <boost/filesystem.hpp>

#include <fstream>
#include <iostream>
#include <stdexcept>

namespace rtlogs
{

    /**
     * Run the single file operation on each of the input arguments
     */
    int single_file_tool::run( int argc, char *argv[])
    {
        using namespace std;
        if (!argc)
        {
            throw_usage_error();
        }
        while (argc)
        {
            // open the file
            ifstream file( argv[0], ios_base::binary);
            if (!file)
            {
                throw runtime_error(
                        string( "could not open file: ") + argv[0]);
            }
            // copy the file contents into a buffer
            file.unsetf( ios_base::skipws);
            std::istreambuf_iterator<char> begin( file), end;
            const buffer_type buffer( begin, end);
            run( buffer, argv[0]);
            --argc;
            ++argv;
        }
        return 0;
    }

    /**
     * Analyze the command line arguments and run the tool on each input file
     * given on the command line
     *
     * If two arguments are given, the first is interpreted as an input file name
     * and the second as an output file name
     *
     * If more than two arguments are provided and the last given argument does not
     * match an existing file name or matches an existing directory, then all other
     * arguments are interpreted as input files and output files will be created in
     * a directory named by the last argument.
     *
     * If more than two arguments are provided and the last argument is also an
     * existing file, or if only one argument is given, all arguments are interpreted
     * as input files and the tool will invent an appropriate name for the output file.
     *
     * The actual tool will then be run for each input-output file pair.
     */
    int input_output_tool::run( int argc, char *argv[])
    {
        std::vector<std::string> arguments( argv, argv + argc);

        harvest_options( arguments);
        handle_options();

        if (arguments.empty())
        {
            throw_usage_error();
        }
        if (arguments.size() == 1)
        {
            // one source, no target specified
            invent_target_name_and_run( arguments[0]);
        }
        else if (arguments.size() == 2)
        {
            // one source, one target specified
            run_with_source_and_target_name( arguments[0], arguments[1]);
        }
        else
        {
            const path destination_dir( arguments[argc - 1]);
            // multiple sources, maybe one target specified.
            if (!exists( destination_dir) || is_directory( destination_dir))
            {
                // multiple sources, one target specified
                for (int arg = 0; arg < argc - 1; ++arg)
                {
                    const path from( arguments[arg]);
                    run_with_source_and_target_name(
                            from,
                            destination_dir / from.filename());
                }
            }
            else
            {
                // multiple sources, no target specified
                for (int arg = 0; arg < argc; ++arg)
                {
                    const path from( arguments[arg]);
                    invent_target_name_and_run( from);
                }
            }
        }

        return 0;
    }

    /**
     * By default, no option handling will be performed.
     */
    void input_output_tool::handle_options()
    {
    }

    /**
     * Construct an appropriate output name for the result from the input name.
     */
    rtlogs::input_output_tool::path input_output_tool::invent_target_name(
        const path &source)
    {
        return source.parent_path() / (prefix + source.filename().string());
    }

    /**
     * Perform simple option parsing.
     *
     * Each argument prefixed with a dash ('-') is interpreted as a single-argument
     * option.
     */
    void input_output_tool::harvest_options( StringVector &arguments)
    {
        auto argument = arguments.begin();
        while (argument != arguments.end())
        {
            if ((*argument)[0] == '-')
            {
                const std::string key = argument->substr( 1);
                argument = arguments.erase( argument);
                if (argument != arguments.end())
                {
                    options[key] = *argument;
                    argument = arguments.erase( argument);
                }
            }
            else
            {
                ++argument;
            }
        }
    }

    /**
     * Run the actual tool with a given input name and an invented output name.
     */
    void input_output_tool::invent_target_name_and_run( const path &source)
    {
        run_with_source_and_target_name( source, invent_target_name( source));
    }

    /**
     * Run the actual tool with a specified input- and output file name.
     *
     * The input file name can be a directory, in which case
     * all files in the input directory will be searched for recursively and parsed.
     */
    void input_output_tool::run_with_source_and_target_name(
        const path &source,
        const path &target)
    {
        if (is_directory( source))
        {
            run_on_directories( source, target);
        }
        else
        {
            if (is_directory( target))
            {
                run_on_file( source, target / source.filename());
            }
            else
            {
                run_on_file( source, target);
            }
        }
    }

    /**
     * Run on all .run files in the given "from" directory recursively and
     * run the actual tool on them. Output files will be created in the given
     * "to" directory.
     */
    void input_output_tool::run_on_directories(
        const path &from,
        const path &to)
    {
        using boost::filesystem::directory_iterator;
        bool directory_created = false;
        using path_vector = std::vector<path>;
        path_vector subdirs;
        for (directory_iterator i( from); i != directory_iterator(); ++i)
        {
            if (is_directory( *i))
            {
                subdirs.push_back( i->path().filename());
            }
            else
            {
                if (i->path().extension() == ".run")
                {
                    if (!directory_created)
                    {
                        create_directories( to);
                        directory_created = true;
                    }
                    run_on_file( i->path(), to / i->path().filename());
                }
            }
        }
        for (const auto &subdir : subdirs)
        {
            run_on_directories( from / subdir, to / subdir.filename());
        }
    }

    void tool_impl::throw_usage_error() const
    {
        throw std::runtime_error( "usage: " + name + " " + argument_help);
    }

}

max_stars_repo_name: DannyHavenith/RunFileParser

max_issues_repo_name: DannyHavenith/RunFileParser

max_forks_repo_name: DannyHavenith/RunFileParser


text:
// Author(s): Sudeep Pillai (spillai@csail.mit.edu)
// License: MIT

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

#include "stl_numpy_converter/utils/template.h"
#include "stl_numpy_converter/utils/container.h"
#include "stl_numpy_converter/utils/optional.h"

#include "stl_numpy_converter/stl_numpy_converter.h"
#include "eigen_numpy_converter/eigen_numpy_converter.h"
#include "opencv_numpy_converter/opencv_numpy_converter.h"

namespace py = boost::python;

namespace pybot {

BOOST_PYTHON_MODULE(pybot_types)
{
  google::InitGoogleLogging("pybot");
  py::scope scope = py::scope();

  // Boost python initializations
  Py_Initialize();
  // import_array();

  // STL converters
  stl_numpy::export_converters();

  // Eigen-numpy converters
  eigen_numpy::export_converters();

  // OpenCV-numpy converters
  opencv_numpy::export_converters();
  opencv_numpy::export_types();

}

}  // namespace pybot

max_stars_repo_name: spillai/pybot

max_issues_repo_name: spillai/pybot

max_forks_repo_name: spillai/pybot


text:
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2012-2015.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////

//! \file

#ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP
#define BOOST_MOVE_DETAIL_META_UTILS_HPP

#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif
#include <boost/move/detail/config_begin.hpp>
#include <boost/move/detail/meta_utils_core.hpp>
#include <boost/move/detail/workaround.hpp> //forceinline
#include <cstddef>                          //for std::size_t

// Small meta-typetraits to support move

namespace boost {

// Forward declare boost::rv
template <class T> class rv;

namespace move_detail {

//////////////////////////////////////
//          is_different
//////////////////////////////////////
template <class T, class U> struct is_different {
  static const bool value = !is_same<T, U>::value;
};

//////////////////////////////////////
//             apply
//////////////////////////////////////
template <class F, class Param> struct apply {
  typedef typename F::template apply<Param>::type type;
};

//////////////////////////////////////
//             bool_
//////////////////////////////////////

template <bool C_> struct bool_ : integral_constant<bool, C_> {
  operator bool() const { return C_; }
  bool operator()() const { return C_; }
};

typedef bool_<true> true_;
typedef bool_<false> false_;

//////////////////////////////////////
//              nat
//////////////////////////////////////
struct nat {};
struct nat2 {};
struct nat3 {};

//////////////////////////////////////
//          yes_type/no_type
//////////////////////////////////////
typedef char yes_type;

struct no_type {
  char _[2];
};

//////////////////////////////////////
//            natify
//////////////////////////////////////
template <class T> struct natify {};

//////////////////////////////////////
//          remove_reference
//////////////////////////////////////
template <class T> struct remove_reference { typedef T type; };

template <class T> struct remove_reference<T &> { typedef T type; };

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct remove_reference<T &&> { typedef T type; };

#else

template <class T> struct remove_reference<rv<T>> { typedef T type; };

template <class T> struct remove_reference<rv<T> &> { typedef T type; };

template <class T> struct remove_reference<const rv<T> &> { typedef T type; };

#endif

//////////////////////////////////////
//             remove_pointer
//////////////////////////////////////

template <class T> struct remove_pointer { typedef T type; };
template <class T> struct remove_pointer<T *> { typedef T type; };
template <class T> struct remove_pointer<T *const> { typedef T type; };
template <class T> struct remove_pointer<T *volatile> { typedef T type; };
template <class T> struct remove_pointer<T *const volatile> { typedef T type; };

//////////////////////////////////////
//             add_pointer
//////////////////////////////////////
template <class T> struct add_pointer {
  typedef typename remove_reference<T>::type *type;
};

//////////////////////////////////////
//             add_const
//////////////////////////////////////
template <class T> struct add_const { typedef const T type; };

template <class T> struct add_const<T &> { typedef const T &type; };

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct add_const<T &&> { typedef T &&type; };

#endif

//////////////////////////////////////
//      add_lvalue_reference
//////////////////////////////////////
template <class T> struct add_lvalue_reference { typedef T &type; };

template <class T> struct add_lvalue_reference<T &> { typedef T &type; };
template <> struct add_lvalue_reference<void> { typedef void type; };
template <> struct add_lvalue_reference<const void> {
  typedef const void type;
};
template <> struct add_lvalue_reference<volatile void> {
  typedef volatile void type;
};
template <> struct add_lvalue_reference<const volatile void> {
  typedef const volatile void type;
};

template <class T> struct add_const_lvalue_reference {
  typedef typename remove_reference<T>::type t_unreferenced;
  typedef typename add_const<t_unreferenced>::type t_unreferenced_const;
  typedef typename add_lvalue_reference<t_unreferenced_const>::type type;
};

//////////////////////////////////////
//             is_lvalue_reference
//////////////////////////////////////
template <class T> struct is_lvalue_reference {
  static const bool value = false;
};

template <class T> struct is_lvalue_reference<T &> {
  static const bool value = true;
};

//////////////////////////////////////
//             identity
//////////////////////////////////////
template <class T> struct identity {
  typedef T type;
  typedef typename add_const_lvalue_reference<T>::type reference;
  reference operator()(reference t) { return t; }
};

//////////////////////////////////////
//          is_class_or_union
//////////////////////////////////////
template <class T> struct is_class_or_union {
  struct twochar {
    char dummy[2];
  };
  template <class U> static char is_class_or_union_tester(void (U::*)(void));
  template <class U> static twochar is_class_or_union_tester(...);
  static const bool value =
      sizeof(is_class_or_union_tester<T>(0)) == sizeof(char);
};

//////////////////////////////////////
//             addressof
//////////////////////////////////////
template <class T> struct addr_impl_ref {
  T &v_;
  BOOST_MOVE_FORCEINLINE addr_impl_ref(T &v) : v_(v) {}
  BOOST_MOVE_FORCEINLINE operator T &() const { return v_; }

private:
  addr_impl_ref &operator=(const addr_impl_ref &);
};

template <class T> struct addressof_impl {
  BOOST_MOVE_FORCEINLINE static T *f(T &v, long) {
    return reinterpret_cast<T *>(
        &const_cast<char &>(reinterpret_cast<const volatile char &>(v)));
  }

  BOOST_MOVE_FORCEINLINE static T *f(T *v, int) { return v; }
};

template <class T> BOOST_MOVE_FORCEINLINE T *addressof(T &v) {
  return ::boost::move_detail::addressof_impl<T>::f(
      ::boost::move_detail::addr_impl_ref<T>(v), 0);
}

//////////////////////////////////////
//          has_pointer_type
//////////////////////////////////////
template <class T> struct has_pointer_type {
  struct two {
    char c[2];
  };
  template <class U> static two test(...);
  template <class U> static char test(typename U::pointer * = 0);
  static const bool value = sizeof(test<T>(0)) == 1;
};

//////////////////////////////////////
//           is_convertible
//////////////////////////////////////
#if defined(_MSC_VER) && (_MSC_VER >= 1400)

// use intrinsic since in MSVC
// overaligned types can't go through ellipsis
template <class T, class U> struct is_convertible {
  static const bool value = __is_convertible_to(T, U);
};

#else

template <class T, class U> class is_convertible {
  typedef typename add_lvalue_reference<T>::type t_reference;
  typedef char true_t;
  class false_t {
    char dummy[2];
  };
  static false_t dispatch(...);
  static true_t dispatch(U);
  static t_reference trigger();

public:
  static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
};

#endif

template <class T, class U, bool IsSame = is_same<T, U>::value>
struct is_same_or_convertible : is_convertible<T, U> {};

template <class T, class U> struct is_same_or_convertible<T, U, true> {
  static const bool value = true;
};

template <bool C, typename F1, typename F2>
struct eval_if_c : if_c<C, F1, F2>::type {};

template <typename C, typename T1, typename T2>
struct eval_if : if_<C, T1, T2>::type {};

#if defined(BOOST_GCC) && (BOOST_GCC <= 40000)
#define BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN
#endif

template <class T, class U, class R = void>
struct enable_if_convertible : enable_if<is_convertible<T, U>, R> {};

template <class T, class U, class R = void>
struct disable_if_convertible : disable_if<is_convertible<T, U>, R> {};

template <class T, class U, class R = void>
struct enable_if_same_or_convertible
    : enable_if<is_same_or_convertible<T, U>, R> {};

template <class T, class U, class R = void>
struct disable_if_same_or_convertible
    : disable_if<is_same_or_convertible<T, U>, R> {};

//////////////////////////////////////////////////////////////////////////////
//
//                         and_
//
//////////////////////////////////////////////////////////////////////////////
template <bool, class B = true_, class C = true_, class D = true_>
struct and_impl : and_impl<B::value, C, D> {};

template <> struct and_impl<true, true_, true_, true_> {
  static const bool value = true;
};

template <class B, class C, class D> struct and_impl<false, B, C, D> {
  static const bool value = false;
};

template <class A, class B, class C = true_, class D = true_>
struct and_ : and_impl<A::value, B, C, D> {};

//////////////////////////////////////////////////////////////////////////////
//
//                            or_
//
//////////////////////////////////////////////////////////////////////////////
template <bool, class B = false_, class C = false_, class D = false_>
struct or_impl : or_impl<B::value, C, D> {};

template <> struct or_impl<false, false_, false_, false_> {
  static const bool value = false;
};

template <class B, class C, class D> struct or_impl<true, B, C, D> {
  static const bool value = true;
};

template <class A, class B, class C = false_, class D = false_>
struct or_ : or_impl<A::value, B, C, D> {};

//////////////////////////////////////////////////////////////////////////////
//
//                         not_
//
//////////////////////////////////////////////////////////////////////////////
template <class T> struct not_ { static const bool value = !T::value; };

//////////////////////////////////////////////////////////////////////////////
//
// enable_if_and / disable_if_and / enable_if_or / disable_if_or
//
//////////////////////////////////////////////////////////////////////////////

template <class R, class A, class B, class C = true_, class D = true_>
struct enable_if_and : enable_if_c<and_<A, B, C, D>::value, R> {};

template <class R, class A, class B, class C = true_, class D = true_>
struct disable_if_and : disable_if_c<and_<A, B, C, D>::value, R> {};

template <class R, class A, class B, class C = false_, class D = false_>
struct enable_if_or : enable_if_c<or_<A, B, C, D>::value, R> {};

template <class R, class A, class B, class C = false_, class D = false_>
struct disable_if_or : disable_if_c<or_<A, B, C, D>::value, R> {};

//////////////////////////////////////////////////////////////////////////////
//
//                      has_move_emulation_enabled_impl
//
//////////////////////////////////////////////////////////////////////////////
template <class T>
struct has_move_emulation_enabled_impl : is_convertible<T, ::boost::rv<T> &> {};

template <class T> struct has_move_emulation_enabled_impl<T &> {
  static const bool value = false;
};

template <class T> struct has_move_emulation_enabled_impl<::boost::rv<T>> {
  static const bool value = false;
};

//////////////////////////////////////////////////////////////////////////////
//
//                            is_rv_impl
//
//////////////////////////////////////////////////////////////////////////////

template <class T> struct is_rv_impl { static const bool value = false; };

template <class T> struct is_rv_impl<rv<T>> { static const bool value = true; };

template <class T> struct is_rv_impl<const rv<T>> {
  static const bool value = true;
};

// Code from Jeffrey Lee Hellrung, many thanks

template <class T> struct is_rvalue_reference {
  static const bool value = false;
};

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct is_rvalue_reference<T &&> {
  static const bool value = true;
};

#else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct is_rvalue_reference<boost::rv<T> &> {
  static const bool value = true;
};

template <class T> struct is_rvalue_reference<const boost::rv<T> &> {
  static const bool value = true;
};

#endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct add_rvalue_reference { typedef T &&type; };

#else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

namespace detail_add_rvalue_reference {
template <class T, bool emulation = has_move_emulation_enabled_impl<T>::value,
          bool rv = is_rv_impl<T>::value>
struct add_rvalue_reference_impl {
  typedef T type;
};

template <class T, bool emulation>
struct add_rvalue_reference_impl<T, emulation, true> {
  typedef T &type;
};

template <class T, bool rv> struct add_rvalue_reference_impl<T, true, rv> {
  typedef ::boost::rv<T> &type;
};
} // namespace detail_add_rvalue_reference

template <class T>
struct add_rvalue_reference
    : detail_add_rvalue_reference::add_rvalue_reference_impl<T> {};

template <class T> struct add_rvalue_reference<T &> { typedef T &type; };

#endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

template <class T> struct remove_rvalue_reference { typedef T type; };

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T> struct remove_rvalue_reference<T &&> { typedef T type; };
#else  // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T> struct remove_rvalue_reference<rv<T>> { typedef T type; };
template <class T> struct remove_rvalue_reference<const rv<T>> {
  typedef T type;
};
template <class T> struct remove_rvalue_reference<volatile rv<T>> {
  typedef T type;
};
template <class T> struct remove_rvalue_reference<const volatile rv<T>> {
  typedef T type;
};
template <class T> struct remove_rvalue_reference<rv<T> &> { typedef T type; };
template <class T> struct remove_rvalue_reference<const rv<T> &> {
  typedef T type;
};
template <class T> struct remove_rvalue_reference<volatile rv<T> &> {
  typedef T type;
};
template <class T> struct remove_rvalue_reference<const volatile rv<T> &> {
  typedef T type;
};
#endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES

// Ideas from Boost.Move review, Jeffrey Lee Hellrung:
//
//- TypeTraits metafunctions is_lvalue_reference, add_lvalue_reference, and
//remove_lvalue_reference ?
//  Perhaps add_reference and remove_reference can be modified so that they
//  behave wrt emulated rvalue references the same as wrt real rvalue
//  references, i.e., add_reference< rv<T>& > -> T& rather than rv<T>& (since
//  T&& & -> T&).
//
//- Add'l TypeTraits has_[trivial_]move_{constructor,assign}...?
//
//- An as_lvalue(T& x) function, which amounts to an identity operation in
//C++0x, but strips emulated
//  rvalue references in C++03.  This may be necessary to prevent "accidental
//  moves".

} // namespace move_detail
} // namespace boost

#include <boost/move/detail/config_end.hpp>

#endif //#ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP

max_stars_repo_name: henrywarhurst/matrix

max_issues_repo_name: henrywarhurst/matrix

max_forks_repo_name: henrywarhurst/matrix


text:
// Copyright 2010-2015 RethinkDB, all rights reserved.
#include <deque>

#include "errors.hpp"
#include <boost/optional.hpp>

#include "unittest/gtest.hpp"

#include "containers/range_map.hpp"
#include "random.hpp"
#include "utils.hpp"

namespace unittest {

class test_range_map_t {
public:
    test_range_map_t() { }
    explicit test_range_map_t(int i) : inner(i), ref_offset(i) {
        validate();
    }
    test_range_map_t(int l, int r, char v) :
        inner(l, r, clone(v)), ref_offset(l), ref(r - l, v)
    {
        validate();
    }
    int left_edge() const {
        int inner_l = inner.left_edge();
        EXPECT_EQ(ref_offset, inner_l);
        return inner_l;
    }
    int right_edge() const {
        int inner_r = inner.right_edge();
        EXPECT_EQ(ref_offset + ref.size(), inner_r);
        return inner_r;
    }
    bool empty_domain() const {
        bool inner_empty = inner.empty_domain();
        EXPECT_EQ(ref.empty(), inner_empty);
        return inner_empty;
    }
    char lookup(int before_point) const {
        char inner_res = inner.lookup(before_point);
        char ref_res = ref.at(before_point - ref_offset);
        EXPECT_EQ(ref_res, inner_res);
        return inner_res;
    }
    template<class callable_t>
    void visit(int l, int r, const callable_t &cb) const {
        int cursor = l;
        boost::optional<char> prev;
        inner.visit(l, r, [&](int l2, int r2, char v) {
            EXPECT_EQ(cursor, l2);
            cursor = r2;
            if (static_cast<bool>(prev)) {
                EXPECT_NE(*prev, v);
            }
            prev = boost::make_optional(v);
            for (int i = l2; i < r2; ++i) {
                EXPECT_EQ(ref.at(i - ref_offset), v);
            }
            cb(l2, r2, v);
        });
        EXPECT_EQ(r, cursor);
    }
    template<class callable_t>
    test_range_map_t map(int l, int r, const callable_t &cb) const {
        test_range_map_t res;
        res.inner = inner.map(l, r, cb);
        res.ref_offset = l;
        for (int i = l; i < r; ++i) {
            res.ref.push_back(cb(ref.at(i - ref_offset)));
        }
        res.validate();
        return res;
    }
    template<class callable_t>
    test_range_map_t map_multi(int l, int r, const callable_t &cb) const {
        test_range_map_t res;
        res.inner = inner.map_multi(l, r, cb);
        res.ref_offset = l;
        for (int i = l; i < r;) {
            int l2 = i;
            while (i < r && ref.at(i - ref_offset) == ref.at(l2 - ref_offset)) ++i;
            int r2 = i;
            range_map_t<int, char> chunk = cb(l2, r2, ref.at(l2 - ref_offset));
            for (int j = l2; j < r2; ++j) {
                res.ref.push_back(chunk.lookup(j));
            }
        }
        res.validate();
        return res;
    }
    test_range_map_t mask(int l, int r) const {
        test_range_map_t res;
        res.inner = inner.mask(l, r);
        res.ref_offset = l;
        res.ref = std::deque<char>(
            ref.begin() + (l - ref_offset),
            ref.begin() + (r - ref_offset));
        res.validate();
        return res;
    }
    void extend_right(test_range_map_t &&other) {
        inner.extend_right(std::move(other.inner));
        ref.insert(ref.end(), other.ref.begin(), other.ref.end());
        validate();
    }
    void extend_right(int l, int r, char v) {
        inner.extend_right(l, r, clone(v));
        while (l++ < r) {
            ref.push_back(v);
        }
        validate();
    }
    void extend_left(test_range_map_t &&other) {
        inner.extend_left(std::move(other.inner));
        ref_offset -= other.ref.size();
        ref.insert(ref.begin(), other.ref.begin(), other.ref.end());
        validate();
    }
    void extend_left(int l, int r, char v) {
        inner.extend_left(l, r, clone(v));
        while (r-- > l) {
            ref.push_front(v);
        }
        ref_offset = l;
        validate();
    }
    void update(test_range_map_t &&other) {
        inner.update(std::move(other.inner));
        for (int i = other.ref_offset;
                i < other.ref_offset + static_cast<int>(other.ref.size());
                ++i) {
            ref.at(i - ref_offset) = other.ref.at(i - other.ref_offset);
        }
        validate();
    }
    void update(int l, int r, char v) {
        inner.update(l, r, clone(v));
        for (int i = l; i < r; ++i) {
            ref.at(i - ref_offset) = v;
        }
        validate();
    }
    template<class callable_t>
    void visit_mutable(int l, int r, const callable_t &cb) {
        int cursor = l;
        boost::optional<char> prev;
        inner.visit_mutable(l, r, [&](int l2, int r2, char *v) {
            EXPECT_EQ(cursor, l2) << "visit_mutable() ranges should be adjacent";
            cursor = r2;
            if (static_cast<bool>(prev)) {
                EXPECT_NE(*prev, *v) << "adjacent ranges should be coalesced";
            }
            prev = boost::make_optional(*v);
            for (int i = l2; i < r2; ++i) {
                EXPECT_EQ(ref.at(i - ref_offset), *v);
            }
            cb(l2, r2, v);
            for (int i = l2; i < r2; ++i) {
                ref.at(i - ref_offset) = *v;
            }
        });
        EXPECT_EQ(r, cursor);
        validate();
    }
    void validate() const {
        bool ok = inner.left_edge() == ref_offset;
        ok = ok && (inner.right_edge() == ref_offset + static_cast<int>(ref.size()));
        inner.visit(inner.left_edge(), inner.right_edge(), [&](int l, int r, char v) {
            for (int i = l; i < r; ++i) {
                ok = ok && (ref.at(i - ref_offset) == v);
            }
        });
        if (!ok) {
            std::string inner_str;
            inner.visit(inner.left_edge(), inner.right_edge(),
                [&](int l, int r, char v) {
                    inner_str += std::string(r - l, v);
                });
            ADD_FAILURE() << "inner/ref mismatch:\n"
                << "inner: " << inner.left_edge()
                    << " '" << inner_str << "' " << inner.right_edge() << "\n"
                << "  ref: " << ref_offset
                    << " '" << as_str() << "' " << ref_offset + ref.size();
        }
    }
    std::string as_str() const {
        return std::string(ref.begin(), ref.end());
    }
    range_map_t<int, char> inner;
    int ref_offset;
    std::deque<char> ref;
};

/* Use a small set of possible chars so that lots of coalescing will happen. */
char rand_char() {
    return 'a' + randint(4);
}

test_range_map_t rand_map(int l, int r) {
    test_range_map_t test(l);
    while (l < r) {
        test.extend_right(l, l + 1, rand_char());
        ++l;
    }
    return test;
}

TEST(RangeMap, RangeMap) {
    test_range_map_t test = rand_map(50, 100);
    for (int repeat = 0; repeat < 1000; ++repeat) {
        int opcode = randint(13);
        int l = test.left_edge() + randint(test.right_edge() - test.left_edge() + 1);
        int r = l + randint(test.right_edge() - l + 1);
        char c = rand_char();
        if (opcode == 0) {
            if (l != test.right_edge()) {
                test.lookup(l);
            }
        } else if (opcode == 1) {
            test.visit(l, r, [&](int, int, char) { });
        } else if (opcode == 2) {
            test = test.map(l, r, [&](char v) -> char { return v + 1; });
        } else if (opcode == 3) {
            test = test.map_multi(l, r, [&](int l2, int r2, char v) {
                range_map_t<int, char> chunk(l2, r2, clone(v));
                chunk.update(l2, l2 + 1, v + 1);
                return chunk;
            });
        } else if (opcode == 4) {
            test = test.mask(l, r);
        } else if (opcode == 5) {
            test.extend_right(
                rand_map(test.right_edge(), test.right_edge() + randint(5)));
        } else if (opcode == 6) {
            int len = randint(5);
            test.extend_right(test.right_edge(), test.right_edge() + len, c);
        } else if (opcode == 7) {
            test.extend_left(
                rand_map(test.left_edge() - randint(5), test.left_edge()));
        } else if (opcode == 8) {
            int len = randint(5);
            test.extend_left(test.left_edge() - len, test.left_edge(), c);
        } else if (opcode == 9) {
            test.update(rand_map(l, r));
        } else if (opcode == 10) {
            test.update(l, r, c);
        } else if (opcode == 11) {
            test.visit_mutable(l, r, [&](int, int, char *v) {
                *v += 1;
            });
        } else if (opcode == 12) {
            test.empty_domain();
        } else {
            unreachable();
        }
    }
}

} /* namespace unittest */

max_stars_repo_name: sauter-hq/rethinkdb

max_issues_repo_name: sauter-hq/rethinkdb

max_forks_repo_name: sauter-hq/rethinkdb