text:
#ifndef WITHOUT_OBSERVATION

#include "stored_queries/StoredAirNuclideQueryHandler.h"
#include "FeatureID.h"
#include "StoredQueryHandlerFactoryDef.h"
#include <boost/format.hpp>
#include <engines/observation/DBRegistry.h>
#include <engines/observation/MastQuery.h>
#include <smartmet/macgyver/Exception.h>
#include <spine/Convenience.h>

namespace bw = SmartMet::Plugin::WFS;

bw::StoredAirNuclideQueryHandler::StoredAirNuclideQueryHandler(
    SmartMet::Spine::Reactor* reactor,
    StoredQueryConfig::Ptr config,
    PluginImpl& plugin_data,
    boost::optional<std::string> template_file_name)

    : bw::StoredQueryParamRegistry(config),
      bw::SupportsExtraHandlerParams(config),
      bw::RequiresGeoEngine(reactor),
      bw::RequiresObsEngine(reactor),
      bw::StoredQueryHandlerBase(reactor, config, plugin_data, template_file_name),
      bw::SupportsLocationParameters(
          reactor, config, INCLUDE_FMISIDS | INCLUDE_GEOIDS | INCLUDE_WMOS | SUPPORT_KEYWORDS),
      bw::SupportsBoundingBox(config, plugin_data.get_crs_registry()),
      bw::SupportsQualityParameters(config)

{
  try
  {
    register_scalar_param<pt::ptime>(P_BEGIN_TIME);
    register_scalar_param<pt::ptime>(P_END_TIME);
    register_scalar_param<std::string>(P_STATION_TYPE);
    register_scalar_param<uint64_t>(P_TIME_STEP);
    register_scalar_param<uint64_t>(P_NUM_OF_STATIONS);
    register_scalar_param<std::string>(P_CRS);
    register_scalar_param<bool>(P_LATEST);
    register_array_param<std::string>(P_NUCLIDE_CODES);

    m_maxHours = config->get_optional_config_param<double>("maxHours", 365 * 24.0);
    m_sqRestrictions = plugin_data.get_config().getSQRestrictions();
    m_supportQCParameters = false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

bw::StoredAirNuclideQueryHandler::~StoredAirNuclideQueryHandler() {}

void bw::StoredAirNuclideQueryHandler::query(const StoredQuery& query,
                                             const std::string& language,
                                             const boost::optional<std::string>& hostname,
                                             std::ostream& output) const
{
  try
  {
    namespace bo = SmartMet::Engine::Observation;
    const auto& params = query.get_param_map();

    // Monitoring query parameter initialization process.
    // If the value is false empty result will be returned.
    bool queryInitializationOK = true;

    try
    {
      const std::string stationType = params.get_single<std::string>(P_STATION_TYPE);
      const double maxDistance = params.get_single<double>(P_MAX_DISTANCE);
      const uint64_t numberOfStations = params.get_single<uint64_t>(P_NUM_OF_STATIONS);
      const std::string requestedCrs = params.get_single<std::string>(P_CRS);
      const bool latest = params.get_single<bool>(P_LATEST);
      const bool showDataQuality = SupportsQualityParameters::supportQualityInfo(params);

      std::vector<std::string> nuclideCodes;
      params.get<std::string>(P_NUCLIDE_CODES, std::back_inserter(nuclideCodes));
      BOOST_FOREACH (auto& n, nuclideCodes)
        n = prepare_nuclide(n);

      const char* DATA_CRS_NAME = "urn:ogc:def:crs:EPSG::4326";
      SmartMet::Spine::CRSRegistry& crs_registry = plugin_impl.get_crs_registry();

      // Output CRS priority: user defined -> default in stored query -> feature type default crs
      const std::string crs = requestedCrs.empty() ? DATA_CRS_NAME : requestedCrs;
      auto transformation = crs_registry.create_transformation(DATA_CRS_NAME, crs);

      bool show_height = false;
      std::string proj_uri = "UNKNOWN";
      std::string proj_epoch_uri = "UNKNOWN";
      std::string axis_labels = "";
      crs_registry.get_attribute(crs, "showHeight", &show_height);
      crs_registry.get_attribute(crs, "projUri", &proj_uri);
      crs_registry.get_attribute(crs, "projEpochUri", &proj_epoch_uri);
      crs_registry.get_attribute(crs, "axisLabels", &axis_labels);

      // Search and validate the locations.
      typedef std::pair<std::string, SmartMet::Spine::LocationPtr> LocationListItem;
      typedef std::list<LocationListItem> LocationList;
      LocationList locations_list;
      get_location_options(params, language, &locations_list);

      const int debug_level = get_config()->get_debug_level();
      if (debug_level > 2)
      {
        BOOST_FOREACH (auto id, locations_list)
          std::cerr << "Found location: name: " << id.first << " geoid: " << id.second->geoid
                    << "\n";
      }

      pt::ptime startTime = params.get_single<pt::ptime>(P_BEGIN_TIME);
      pt::ptime endTime = params.get_single<pt::ptime>(P_END_TIME);
      const uint64_t timestep = params.get_single<uint64_t>(P_TIME_STEP);

      if (m_sqRestrictions)
        check_time_interval(startTime, endTime, m_maxHours);

      // Only 24 hours allowed
      if (1440 < timestep)
      {
        Fmi::Exception exception(BCP, "Operation processing failed!");
        exception.addDetail("Invalid time step value. Maximum is 1440 minutes.");
        exception.addParameter(WFS_EXCEPTION_CODE, WFS_INVALID_PARAMETER_VALUE);
        exception.addParameter("Timestep", std::to_string(timestep));
        throw exception.disableStackTrace();
      }

      // Get all the information needed in a OBsEngine station search.
      SmartMet::Engine::Observation::Settings stationSearchSettings;
      stationSearchSettings.allplaces = false;
      stationSearchSettings.numberofstations = numberOfStations;
      stationSearchSettings.stationtype = stationType;
      stationSearchSettings.maxdistance = maxDistance;
      stationSearchSettings.useDataCache = false;
      stationSearchSettings.starttime = startTime;
      stationSearchSettings.endtime = endTime;

      SmartMet::Engine::Observation::StationSettings stationSettings;

      // Include valid locations.
      for (const auto& item : locations_list)
      {
        stationSettings.nearest_station_settings.emplace_back(item.second->longitude,
                                                              item.second->latitude,
                                                              maxDistance,
                                                              1,
                                                              item.first,
                                                              item.second->fmisid);
      }

      // Bounding box search options.
      SmartMet::Spine::BoundingBox requested_bbox;
      bool have_bbox = get_bounding_box(params, crs, &requested_bbox);
      if (have_bbox)
      {
        std::unique_ptr<SmartMet::Spine::BoundingBox> query_bbox;
        query_bbox.reset(new SmartMet::Spine::BoundingBox);
        *query_bbox =
            bw::SupportsBoundingBox::transform_bounding_box(requested_bbox, DATA_CRS_NAME);
        SmartMet::Engine::Observation::Settings bboxSettings;
        stationSettings.bounding_box_settings["minx"] = query_bbox->xMin;
        stationSettings.bounding_box_settings["miny"] = query_bbox->yMin;
        stationSettings.bounding_box_settings["maxx"] = query_bbox->xMax;
        stationSettings.bounding_box_settings["maxy"] = query_bbox->yMax;
      }

      stationSearchSettings.taggedFMISIDs =
          obs_engine->translateToFMISID(stationSearchSettings.starttime,
                                        stationSearchSettings.endtime,
                                        stationSearchSettings.stationtype,
                                        stationSettings);

      // Search stations based on location settings.
      // The result does not contain duplicates.
      SmartMet::Spine::Stations stationCandidates;
      obs_engine->getStations(stationCandidates, stationSearchSettings);

      std::string langCode = language;
      SupportsLocationParameters::engOrFinToEnOrFi(langCode);

      // Get information from GeoEngien. Elevation is required.
      typedef std::map<std::string, SmartMet::Spine::Station> StationMap;
      StationMap stations;
      // SmartMet::Spine::Stations stations;
      for (SmartMet::Spine::Stations::const_iterator it = stationCandidates.begin();
           it != stationCandidates.end();
           ++it)
      {
        std::string fmisidStr = std::to_string((*it).fmisid);
        stations.emplace(fmisidStr, *it);

        SmartMet::Spine::LocationPtr geoLoc = geo_engine->idSearch(it->geoid, langCode);
        if (geoLoc)
        {
          stations[fmisidStr].country = geoLoc->country;
          stations[fmisidStr].station_elevation = geoLoc->elevation;
        }
      }

      if (stations.empty())
        queryInitializationOK = false;

      //
      // Observation ID search
      //

      // Using OBSERVATIONS_V2 as a base configuration
      // Creating query parameters object by using the base configuration.
      // All the other configurations are joined to this.
      bo::MastQueryParams stationQueryParams(dbRegistryConfig("OBSERVATIONS_V2"));

      // Join on STATIONS_V1 view by using STATION_ID
      stationQueryParams.addJoinOnConfig(dbRegistryConfig("STATIONS_V1"), "STATION_ID");

      stationQueryParams.addJoinOnConfig(dbRegistryConfig("NETWORK_MEMBERS_V1"), "STATION_ID");

      stationQueryParams.addJoinOnConfig(dbRegistryConfig("STUK_RADIONUCLIDE_ANALYSES_V1"),
                                         "STATION_ID");

      // Station identities
      for (StationMap::const_iterator it = stations.begin();
           queryInitializationOK && it != stations.end();
           ++it)
      {
        stationQueryParams.addOperation(
            "OR_GROUP_station_id", "STATION_ID", "PropertyIsEqualTo", it->second.fmisid);
      }

      stationQueryParams.addOperation(
          "OR_GROUP_network_id", "NETWORK_ID", "PropertyIsEqualTo", 59);  // STUK-ILMA-verkko (59)

      std::string paramName = "AC_P7D_avg";
      // Is the parameter configured in Observation
      const uint64_t paramId = obs_engine->getParameterId(paramName, stationType);
      if (not paramId)
      {
        Fmi::Exception exception(BCP, "Unknown parameter in the query!");
        exception.addParameter(WFS_EXCEPTION_CODE, WFS_INVALID_PARAMETER_VALUE);
        exception.addParameter("Unknown parameter", paramName);
        throw exception.disableStackTrace();
      }

      stationQueryParams.addOperation(
          "OR_GROUP_measurand_id", "MEASURAND_ID", "PropertyIsEqualTo", paramId);

      stationQueryParams.addOperation(
          "OR_GROUP_end_time", "PERIOD_START", "PropertyIsLessThanOrEqualTo", endTime);
      stationQueryParams.addOperation(
          "OR_GROUP_start_time", "PERIOD_END", "PropertyIsGreaterThanOrEqualTo", startTime);
      stationQueryParams.addOperation(
          "OR_GROUP_atime", "ANALYSIS_TIME", "PropertyIsGreaterThanOrEqualTo", startTime);

      stationQueryParams.addField("ANALYSIS_TIME");
      stationQueryParams.addField("STATION_ID");
      stationQueryParams.addField("ANALYSIS_ID");
      stationQueryParams.addOrderBy("ANALYSIS_TIME", "DESC");
      stationQueryParams.addOrderBy("STATION_ID", "ASC");

      bo::MastQuery profileQuery;
      profileQuery.setQueryParams(&stationQueryParams);
      if (queryInitializationOK)
      {
        obs_engine->makeQuery(&profileQuery);
      }

      // Container with the observation identities of the requested stations.
      std::shared_ptr<bo::QueryResult> profileContainer = profileQuery.getQueryResultContainer();

      bo::MastQuery dataQuery;

      bo::MastQuery radioNuclidesQuery;
      typedef std::map<std::string, std::string> NuclideNameMap;
      NuclideNameMap nuclideNameMap;

      // At least one observation_id is required for data search.
      if (not profileContainer or (profileContainer->size("ANALYSIS_ID") == 0))
      {
        queryInitializationOK = false;
      }
      else
      {
        //
        // Get the data match with the analysis_id values
        //

        // Using STUK_RADIONUCLIDE_ANALYSES_V1 as a base configuration
        bo::MastQueryParams dataQueryParams(dbRegistryConfig("STUK_RADIONUCLIDE_ANALYSES_V1"));
        dataQueryParams.addJoinOnConfig(dbRegistryConfig("STUK_RADIONUCLIDE_DATA_V1"),
                                        "ANALYSIS_ID");

        bo::QueryResult::ValueVectorType::const_iterator analysisIdIt =
            profileContainer->begin("ANALYSIS_ID");
        bo::QueryResult::ValueVectorType::const_iterator analysisIdItEnd =
            profileContainer->end("ANALYSIS_ID");
        bo::QueryResult::ValueVectorType::const_iterator stationIdIt =
            profileContainer->begin("STATION_ID");

        // Getting nuclide names in finnish or english
        bo::MastQueryParams radioNuclidesQueryParams(dbRegistryConfig("STUK_RADIONUCLIDES_VL1"));
        radioNuclidesQueryParams.addJoinOnConfig(dbRegistryConfig("STUK_RADIONUCLIDES_V1"),
                                                 "NUCLIDE_ID");
        radioNuclidesQueryParams.addOperation(
            "OR_GROUP_language_code", "LANGUAGE_CODE", "PropertyIsEqualTo", langCode);

        std::vector<std::string>::const_iterator nucCodeIt = nuclideCodes.begin();
        for (; queryInitializationOK && nucCodeIt != nuclideCodes.end(); ++nucCodeIt)
          radioNuclidesQueryParams.addOperation("OR_GROUP_nuclide_code",
                                                "NUCLIDE_CODE",
                                                "PropertyIsEqualTo",
                                                std::string(*nucCodeIt));

        radioNuclidesQueryParams.addField("NUCLIDE_CODE");
        radioNuclidesQueryParams.addField("NUCLIDE_NAME");
        radioNuclidesQueryParams.useDistinct();

        radioNuclidesQuery.setQueryParams(&radioNuclidesQueryParams);
        obs_engine->makeQuery(&radioNuclidesQuery);

        std::shared_ptr<bo::QueryResult> radioNuclidesContainer =
            radioNuclidesQuery.getQueryResultContainer();

        if (radioNuclidesContainer->size())
        {
          bo::QueryResult::ValueVectorType::const_iterator nCodeIt =
              radioNuclidesContainer->begin("NUCLIDE_CODE");
          bo::QueryResult::ValueVectorType::const_iterator nCodeItEnd =
              radioNuclidesContainer->end("NUCLIDE_CODE");
          bo::QueryResult::ValueVectorType::const_iterator nNameIt =
              radioNuclidesContainer->begin("NUCLIDE_NAME");

          for (; nCodeIt != nCodeItEnd; ++nCodeIt, ++nNameIt)
          {
            nuclideNameMap.emplace(bo::QueryResult::toString(nCodeIt),
                                   bo::QueryResult::toString(nNameIt));
          }
        }

        typedef std::set<int> LatestSet;
        LatestSet latestSet;
        for (; queryInitializationOK && analysisIdIt != analysisIdItEnd;
             ++analysisIdIt, ++stationIdIt)
        {
          // Select only latest if wanted.
          if (latest)
          {
            const int tmpstationId = std::stoi(bo::QueryResult::toString(stationIdIt, 0));
            LatestSet::const_iterator latestSetIt = latestSet.find(tmpstationId);
            if (latestSetIt == latestSet.end())
            {
              latestSet.insert(tmpstationId);
              int tmpAnalysisId = std::stoi(bo::QueryResult::toString(analysisIdIt, 0));
              dataQueryParams.addOperation(
                  "OR_GROUP_analysis_id", "ANALYSIS_ID", "PropertyIsEqualTo", tmpAnalysisId);
            }
          }
          else
          {
            int tmpAnalysisId = std::stoi(bo::QueryResult::toString(analysisIdIt, 0));
            dataQueryParams.addOperation(
                "OR_GROUP_analysis_id", "ANALYSIS_ID", "PropertyIsEqualTo", tmpAnalysisId);
          }
        }

        std::vector<std::string>::const_iterator nuclideCodeIt = nuclideCodes.begin();
        for (; queryInitializationOK && nuclideCodeIt != nuclideCodes.end(); ++nuclideCodeIt)
          dataQueryParams.addOperation("OR_GROUP_nuclide_code",
                                       "NUCLIDE_CODE",
                                       "PropertyIsEqualTo",
                                       std::string(*nuclideCodeIt));

        dataQueryParams.addField("ANALYSIS_ID");
        dataQueryParams.addField("STATION_ID");
        dataQueryParams.addField("OBSERVATION_ID");
        dataQueryParams.addField("PERIOD_START");
        dataQueryParams.addField("PERIOD_END");
        dataQueryParams.addField("ANALYSIS_TIME");
        dataQueryParams.addField("ANALYSIS_VERSION");
        dataQueryParams.addField("AIR_VOLUME");
        dataQueryParams.addField("NUCLIDE_CODE");
        dataQueryParams.addField("DATA_QUALITY");
        dataQueryParams.addField("CONCENTRATION");
        dataQueryParams.addField("UNCERTAINTY");

        dataQueryParams.addOrderBy("STATION_ID", "ASC");
        dataQueryParams.addOrderBy("OBSERVATION_ID", "ASC");
        dataQueryParams.addOrderBy("ANALYSIS_ID", "ASC");
        dataQueryParams.addOrderBy("CONCENTRATION", "DESC");

        dataQuery.setQueryParams(&dataQueryParams);

        if (queryInitializationOK)
          obs_engine->makeQuery(&dataQuery);
      }

      // Get the sequence number of query in the request
      int sq_id = query.get_query_id();
      FeatureID feature_id(get_config()->get_query_id(), params.get_map(), sq_id);
      const std::string fullFeatureId = feature_id.get_id();

      // Removing some feature id parameters
      const char* place_params[] = {
          P_WMOS, P_FMISIDS, P_PLACES, P_LATLONS, P_GEOIDS, P_KEYWORD, P_BOUNDING_BOX};
      for (unsigned i = 0; i < sizeof(place_params) / sizeof(*place_params); i++)
      {
        feature_id.erase_param(place_params[i]);
      }

      //
      // Fill data for xml formatting.
      //
      CTPP::CDT hash;

      params.dump_params(hash["query_parameters"]);
      dump_named_params(params, hash["named_parameters"]);

      hash["featureId"] = feature_id.get_id();

      hash["responseTimestamp"] =
          pt::to_iso_extended_string(get_plugin_impl().get_time_stamp()) + "Z";
      hash["fmi_apikey"] = QueryBase::FMI_APIKEY_SUBST;
      hash["fmi_apikey_prefix"] = bw::QueryBase::FMI_APIKEY_PREFIX_SUBST;
      hash["hostname"] = QueryBase::HOSTNAME_SUBST;
      hash["protocol"] = QueryBase::PROTOCOL_SUBST;
      hash["language"] = language;
      hash["projSrsDim"] = (show_height ? 3 : 2);
      hash["projSrsName"] = proj_uri;
      hash["projEpochSrsDim"] = (show_height ? 4 : 3);
      hash["projEpochSrsName"] = proj_epoch_uri;
      hash["axisLabels"] = axis_labels;
      hash["queryNum"] = query.get_query_id();
      hash["queryName"] = get_query_name();
      hash["stationType"] = stationType;

      std::shared_ptr<bo::QueryResult> dataContainer = dataQuery.getQueryResultContainer();

      int numberMatched = 0;
      if (queryInitializationOK and profileContainer and dataContainer)
      {
        bo::QueryResult::ValueVectorType::const_iterator analysisIdIt =
            dataContainer->begin("ANALYSIS_ID");
        bo::QueryResult::ValueVectorType::const_iterator stationIdIt =
            dataContainer->begin("STATION_ID");
        bo::QueryResult::ValueVectorType::const_iterator stationIdItEnd =
            dataContainer->end("STATION_ID");
        bo::QueryResult::ValueVectorType::const_iterator observationIdIt =
            dataContainer->begin("OBSERVATION_ID");
        bo::QueryResult::ValueVectorType::const_iterator periodStartIt =
            dataContainer->begin("PERIOD_START");
        bo::QueryResult::ValueVectorType::const_iterator periodEndIt =
            dataContainer->begin("PERIOD_END");
        bo::QueryResult::ValueVectorType::const_iterator analysisTimeIt =
            dataContainer->begin("ANALYSIS_TIME");
        bo::QueryResult::ValueVectorType::const_iterator analysisVersionIt =
            dataContainer->begin("ANALYSIS_VERSION");
        bo::QueryResult::ValueVectorType::const_iterator airVolumeIt =
            dataContainer->begin("AIR_VOLUME");
        bo::QueryResult::ValueVectorType::const_iterator nuclideCodeIt =
            dataContainer->begin("NUCLIDE_CODE");
        bo::QueryResult::ValueVectorType::const_iterator concentrationIt =
            dataContainer->begin("CONCENTRATION");
        bo::QueryResult::ValueVectorType::const_iterator dataQualityIt =
            dataContainer->begin("DATA_QUALITY");
        bo::QueryResult::ValueVectorType::const_iterator uncertaintyIt =
            dataContainer->begin("UNCERTAINTY");

        std::string currentAnalysisIdStr = "dummyAnalysisId";
        int groupId = 0;

        for (; stationIdIt != stationIdItEnd;)
        {
          std::string stationIdStr = bo::QueryResult::toString(stationIdIt, 0);
          std::string observationIdStr = bo::QueryResult::toString(observationIdIt, 0);
          std::string analysisIdStr = bo::QueryResult::toString(analysisIdIt, 0);
          std::string periodStartStr = bo::QueryResult::toString(periodStartIt);
          std::string periodEndStr = bo::QueryResult::toString(periodEndIt);

          StationMap::const_iterator sit = stations.find(stationIdStr);
          if (sit == stations.end())
          {
            std::ostringstream msg;
            msg << "SmartMet::Plugin::WFS::StoredAirNuclideQueryHandler : missing station data ("
                << stationIdStr << "\n";
            break;
          }

          // Group is an analysis of an observation in a station.
          CTPP::CDT& group = hash["groups"][groupId];
          const std::string groupId_str = str(boost::format("%1%-%2%") % sq_id % (groupId + 1));
          group["groupId"] = groupId_str;
          group["groupNum"] = groupId + 1;
          group["obsParamList"][0]["name"] = paramName;

          if (not sit->second.station_formal_name.empty())
            group["stationFormalName"] = sit->second.station_formal_name;
          if (not sit->second.region.empty())
            group["region"] = sit->second.region;
          if (not sit->second.country.empty())
            group["country"] = sit->second.country;

          set_2D_coord(transformation, sit->second.latitude_out, sit->second.longitude_out, group);

          group["latitude"] = std::to_string(sit->second.latitude_out);
          group["longitude"] = std::to_string(sit->second.longitude_out);
          if (show_height)
            group["elevation"] = std::to_string(sit->second.station_elevation);

          group["fmisid"] = stationIdStr;
          group["observationId"] = observationIdStr;
          group["analysisId"] = analysisIdStr;
          group["obsPhenomenonStartTime"] = periodStartStr;
          group["obsPhenomenonEndTime"] = periodEndStr;

          group["analysisTime"] = bo::QueryResult::toString(analysisTimeIt);
          group["obsResultTime"] = bo::QueryResult::toString(analysisTimeIt);
          group["analysisVersion"] = bo::QueryResult::toString(analysisVersionIt);
          group["airVolume"] = bo::QueryResult::toString(airVolumeIt);

          // Using the exact time period of measurement in featureId search.
          feature_id.erase_param(P_BEGIN_TIME);
          feature_id.erase_param(P_END_TIME);
          feature_id.add_param(P_BEGIN_TIME, periodStartStr);
          feature_id.add_param(P_END_TIME, periodEndStr);

          // Using fmisid for selecting a location in featureId search.
          feature_id.erase_param(P_FMISIDS);
          feature_id.add_param(P_FMISIDS, sit->second.fmisid);

          const std::string analysisfeatureId = feature_id.get_id();

          group["featureId"] = analysisfeatureId;

          int ind = 0;

          currentAnalysisIdStr = analysisIdStr;
          for (; (stationIdIt != stationIdItEnd) and
                 (currentAnalysisIdStr == bo::QueryResult::toString(analysisIdIt, 0));
               ++analysisIdIt,
               ++stationIdIt,
               ++observationIdIt,
               ++periodStartIt,
               ++periodEndIt,
               ++analysisTimeIt,
               ++analysisVersionIt,
               ++airVolumeIt,
               ++nuclideCodeIt,
               ++concentrationIt,
               ++dataQualityIt,
               ++uncertaintyIt)
          {
            const std::string nCode = bo::QueryResult::toString(nuclideCodeIt);
            group["data"][ind]["nuclideCode"] = nCode;
            NuclideNameMap::const_iterator nNameIt = nuclideNameMap.find(nCode);
            if (nNameIt != nuclideNameMap.end())
              group["data"][ind]["nuclideName"] = nNameIt->second;

            group["data"][ind]["concentration"] = bo::QueryResult::toString(concentrationIt, 2);
            if (showDataQuality)
              group["data"][ind]["dataQuality"] = bo::QueryResult::toString(dataQualityIt, 0);
            group["data"][ind]["uncertainty"] = bo::QueryResult::toString(uncertaintyIt, 0);

            ind++;
          }

          numberMatched++;
          groupId++;
        }
      }

      hash["numberMatched"] = numberMatched;
      hash["numberReturned"] = numberMatched;
      format_output(hash, output, query.get_use_debug_format());
    }
    catch (...)
    {
      Fmi::Exception exception(BCP, "Operation processing failed!", nullptr);
      if (exception.getExceptionByParameterName(WFS_EXCEPTION_CODE) == nullptr)
        exception.addParameter(WFS_EXCEPTION_CODE, WFS_OPERATION_PROCESSING_FAILED);
      exception.addParameter(WFS_LANGUAGE, language);
      throw exception;
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

std::string bw::StoredAirNuclideQueryHandler::prepare_nuclide(const std::string& nuclide) const
{
  try
  {
    std::string out = nuclide;
    boost::algorithm::trim(out);

    const size_t size = out.size();
    if (size < 3)
    {
      Fmi::Exception exception(BCP, "Invalid parameter value!");
      exception.addDetail("Too short nuclide code. Minimum length is 3.");
      exception.addParameter(WFS_EXCEPTION_CODE, "WFS_INVALID_PARAMETER_VALUE");
      exception.addParameter("Nuclide code", out);
      throw exception;
    }

    if (size > 8)
    {
      Fmi::Exception exception(BCP, "Invalid parameter value!");
      exception.addDetail("Too long nuclide code. Maximum length is 8.");
      exception.addParameter(WFS_EXCEPTION_CODE, WFS_INVALID_PARAMETER_VALUE);
      exception.addParameter("Nuclide code", out);
      throw exception;
    }

    // Nuclide code must begin with upper_case char.
    // It has always '-' char and after that some number.
    // It may end with char.
    // E.g "Cs-137" or "Pm-148M".
    std::string nuclide_upper = Fmi::ascii_toupper_copy(out);
    Fmi::ascii_tolower(out);
    out.at(0) = nuclide_upper.at(0);
    out.at(size - 1) = nuclide_upper.at(size - 1);

    using boost::spirit::ascii::space;
    using boost::spirit::qi::char_;
    using boost::spirit::qi::eps;
    using boost::spirit::qi::lower;
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::qi::upper;
    using boost::spirit::qi::ushort_;

    std::string::const_iterator first = out.begin();
    std::string::const_iterator last = out.end();

    phrase_parse(first, last, upper >> *lower >> char_('-') >> ushort_ >> (upper | eps), space);
    if (first != last)
    {
      Fmi::Exception exception(BCP, "Invalid parameter value!");
      exception.addDetail("Unrecognized nuclide code.");
      exception.addParameter(WFS_EXCEPTION_CODE, WFS_INVALID_PARAMETER_VALUE);
      exception.addParameter("Nuclide code", out);
      throw exception;
    }

    return out;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

const std::shared_ptr<SmartMet::Engine::Observation::DBRegistryConfig>
bw::StoredAirNuclideQueryHandler::dbRegistryConfig(const std::string& configName) const
{
  try
  {
    // Get database registry from Engine::Observation.
    const std::shared_ptr<SmartMet::Engine::Observation::DBRegistry> dbRegistry =
        obs_engine->dbRegistry();
    if (not dbRegistry)
    {
      Fmi::Exception exception(BCP, "Database registry is not available!");
      exception.addParameter(WFS_EXCEPTION_CODE, WFS_OPERATION_PROCESSING_FAILED);
      throw exception;
    }

    const std::shared_ptr<SmartMet::Engine::Observation::DBRegistryConfig> dbrConfig =
        dbRegistry->dbRegistryConfig(configName);
    if (not dbrConfig)
    {
      Fmi::Exception exception(BCP,
                                           "Database registry configuration is not available!");
      exception.addParameter(WFS_EXCEPTION_CODE, WFS_OPERATION_PROCESSING_FAILED);
      exception.addParameter("Configration name", configName);
      throw exception;
    }

    return dbrConfig;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

namespace
{
using namespace SmartMet::Plugin::WFS;

boost::shared_ptr<SmartMet::Plugin::WFS::StoredQueryHandlerBase>
wfs_stored_air_nuclide_handler_create(SmartMet::Spine::Reactor* reactor,
                                      StoredQueryConfig::Ptr config,
                                      PluginImpl& plugin_data,
                                      boost::optional<std::string> template_file_name)
{
  try
  {
    bw::StoredAirNuclideQueryHandler* qh =
        new bw::StoredAirNuclideQueryHandler(reactor, config, plugin_data, template_file_name);
    boost::shared_ptr<SmartMet::Plugin::WFS::StoredQueryHandlerBase> instance(qh);
    return instance;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}
}  // namespace

SmartMet::Plugin::WFS::StoredQueryHandlerFactoryDef wfs_stored_air_nuclide_handler_factory(
    &wfs_stored_air_nuclide_handler_create);

/**

@page WFS_SQ_AIR_NUCLIDE_QUERY_HANDLER Stored Query handler for querying Air Radionuclide activity
concentration data

@section WFS_SQ_AIR_NUCLIDE_QUERY_HANDLER_INTRO Introduction

The stored query handler provide access to the Air Radionuclide activity concentration data.

<table border="1">
  <tr>
     <td>Implementation</td>
     <td>SmartMet::Plugin::WFS::StoredAirNuclideQueryHandler</td>
  </tr>
  <tr>
    <td>Constructor name (for stored query configuration)</td>
    <td>@b wfs_stored_air_nuclide_handler_factory</td>
  </tr>
</table>

@section WFS_SQ_AIR_NUCLIDE_QUERY_HANDLER_PARAMS Stored query handler built-in parameters

The following stored query handler parameters are being used by this stored query handler:

- @ref WFS_SQ_PARAM_BBOX
- @ref WFS_SQ_LOCATION_PARAMS
- @ref WFS_SQ_QUALITY_PARAMS

<table border="1">

<tr>
<th>Entry name</th>
<th>Type</th>
<th>Data type</th>
<th>Description</th>
</tr>

<tr>
  <td>beginTime</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>time</td>
  <td>Specifies the time of the begin of time interval</td>
</tr>

<tr>
  <td>endTime</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>time</td>
  <td>Specifies the time of the end of time interval</td>
</tr>

<tr>
  <td>nuclideCodes</td>
  <td>@ref WFS_CFG_ARRAY_PARAM_TMPL</td>
  <td>string</td>
  <td>Specifies a list of nuclides. If at least one listed nuclide
      match with a nuclide in a analysis, the analysis will be included into the result.
      In case of empty list match of nuclide will be ignored.</td>
</tr>

<tr>
  <td>geoids</td>
  <td>@ref WFS_CFG_ARRAY_PARAM_TMPL</td>
  <td>int</td>
  <td>Maps to stored query array parameter containing GEOID values for stations. Note that
      this parameter may be left out by constructor parameter.</td>
</tr>

<tr>
  <td>places</td>
  <td>@ref WFS_CFG_ARRAY_PARAM_TMPL</td>
  <td>string</td>
  <td>Maps to the place names like 'Helsinki'</td>
</tr>

<tr>
  <td>stationType</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>string</td>
  <td>Specifies station type.</td>
</tr>

<tr>
  <td>fmisids</td>
  <td>@ref WFS_CFG_ARRAY_PARAM_TMPL</td>
  <td>integer</td>
  <td>Specifies stations FMISID codes</td>
</tr>

<tr>
  <td>numOfStations</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>unsigned integer</td>
  <td>Specifies how many nearest stations to select with distance less than @b maxDistance
      (see @ref WFS_SQ_LOCATION_PARAMS "location parameters" for details)</td>
</tr>

<tr>
  <td>latest</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>bool</td>
  <td>To return latest (true) values from stations or all (false).</td>
</tr>

</table>

@section WFS_SQ_AIR_NUCLIDE_QUERY_HANDLER_EXTRA_CFG_PARAM Additional parameters

This section describes this stored query handler configuration parameters which does not map to
stored query parameters
and must be specified on top level of stored query configuration file when present

<table border="1">

<tr>
<th>Entry name</th>
<th>Type</th>
<th>Use</th>
<th>Description</th>
</tr>

<tr>
  <td>supportQCParameters</td>
  <td>@ref WFS_CFG_SCALAR_PARAM_TMPL</td>
  <td>boolean</td>
  <td>Specifies support of quality code parameters. Quality code parameters are as the normal meteo
parameters but prefixed with "qc_" string. Default value is \b false.</td>
</tr>

</table>

*/

#endif  // WITHOUT_OBSERVATION

max_stars_repo_name: nakkim/smartmet-plugin-wfs

max_issues_repo_name: nakkim/smartmet-plugin-wfs

max_forks_repo_name: nakkim/smartmet-plugin-wfs


text:
/*!
@file
Forward declares `boost::hana::detail::nested_by`.

@copyright Louis Dionne 2013-2016
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_DETAIL_NESTED_BY_FWD_HPP
#define BOOST_HANA_DETAIL_NESTED_BY_FWD_HPP

#include <boost/hana/config.hpp>

BOOST_HANA_NAMESPACE_BEGIN namespace detail {
    template <typename Algorithm>
    struct nested_by_t {
        template <typename Predicate, typename Object>
        constexpr decltype(auto)
        operator()(Predicate&& predicate, Object&& object) const;

        template <typename Predicate>
        constexpr decltype(auto) operator()(Predicate&& predicate) const;
    };

    //! @ingroup group-details
    //! Provides a `.by` static constexpr function object.
    //!
    //! When creating a binary function object of type `Algorithm` whose
    //! signature is `Object x Predicate -> Return`, `nested_by<Algorithm>`
    //! can be used as a base class to `Algorithm`. Doing so will provide a
    //! static constexpr member called `by`, which has the two following
    //! signatures:
    //! @code
    //!     Predicate x Object -> Return
    //!     Predicate -> (Object -> Return)
    //! @endcode
    //!
    //! In other words, `nested_by` is a `curry`ed and `flip`ped version of
    //! `Algorithm`. Note that the function object `Algorithm` must be
    //! default-constructible, since the algorithm will be called as
    //! `Algorithm{}(arguments...)`.
    //!
    //! @note
    //! This function object is especially useful because it takes care of
    //! avoiding ODR violations caused by the nested static constexpr member.
    template <typename Algorithm>
    struct nested_by { static constexpr nested_by_t<Algorithm> by{}; };

    template <typename Algorithm>
    constexpr nested_by_t<Algorithm> nested_by<Algorithm>::by;
} BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_DETAIL_NESTED_BY_FWD_HPP

ext: hpp

max_stars_repo_name: rudylee/expo

max_issues_repo_name: rudylee/expo

max_forks_repo_name: rudylee/expo


text:
//  boost run_timer.cpp  ---------------------------------------------------------------//

//  Copyright Beman Dawes 1994, 2006, 2008
//  Copyright 2009-2010 Vicente J. Botet Escriba

//  Distributed under the Boost Software License, Version 1.0.
//  See http://www.boost.org/LICENSE_1_0.txt

//  See http://www.boost.org/libs/chrono for documentation.

//--------------------------------------------------------------------------------------//
#ifndef BOOST_CHRONO_DETAIL_INLINED_RUN_TIMER_HPP
#define BOOST_CHRONO_DETAIL_INLINED_RUN_TIMER_HPP

#include <boost/version.hpp>
#include <boost/chrono/process_times.hpp>
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <boost/io/ios_state.hpp>
#include <cstring>
#include <boost/assert.hpp>

namespace boost
{
namespace chrono
{
namespace chrono_detail
{
  BOOST_CHRONO_INLINE
  const char * default_format() {
    return "\nreal %rs, cpu %cs (%p%), user %us, system %ss\n";
  }

  BOOST_CHRONO_INLINE
  void show_time( const boost::chrono::process_times & times,
                  const char * format, int places, std::ostream & os )
  //  NOTE WELL: Will truncate least-significant digits to LDBL_DIG, which may
  //  be as low as 10, although will be 15 for many common platforms.
  {
    if ( times.real < nanoseconds(0) ) return;
    if ( places > 9 )
      places = 9;  // sanity check
    else if ( places < 0 )
      places = 0;

    boost::io::ios_flags_saver ifs( os );
    os.setf( std::ios_base::fixed, std::ios_base::floatfield );
    boost::io::ios_precision_saver ips( os );
    os.precision( places );

    nanoseconds total = times.system + times.user;

    for ( ; *format; ++format )
    {
      if ( *format != '%' || !*(format+1) || !std::strchr("rcpus", *(format+1)) )
        os << *format;
      else
      {
        ++format;
        switch ( *format )
        {
        case 'r':
          os << duration<double>(times.real).count();
          break;
        case 'u':
          os << duration<double>(times.user).count();
          break;
        case 's':
          os << duration<double>(times.system).count();
          break;
        case 'c':
          os << duration<double>(total).count();
          break;
        case 'p':
          {
            boost::io::ios_precision_saver ips( os );
            os.precision( 1 );
            if ( times.real.count() && total.count() )
              os << duration<double>(total).count()
                   /duration<double>(times.real).count() * 100.0;
            else
              os << 0.0;
          }
          break;
        default:
          BOOST_ASSERT(0 && "run_timer internal logic error");
        }
      }
    }
  }

}

      run_timer::run_timer( system::error_code & ec  )
        : m_places(m_default_places), m_os(m_cout()) { start(ec); }
      run_timer::run_timer( std::ostream & os,
        system::error_code & ec  )
        : m_places(m_default_places), m_os(os) { start(ec); }

      run_timer::run_timer( const std::string & format,
        system::error_code & ec  )
        : m_places(m_default_places), m_os(m_cout()), m_format(format) { start(ec); }
      run_timer::run_timer( std::ostream & os, const std::string & format,
        system::error_code & ec  )
        : m_places(m_default_places), m_os(os), m_format(format) { start(ec); }

      run_timer::run_timer( const std::string & format, int places,
        system::error_code & ec  )
        : m_places(places), m_os(m_cout()), m_format(format) { start(ec); }
      run_timer::run_timer( std::ostream & os, const std::string & format,
        int places, system::error_code & ec  )
        : m_places(places), m_os(os), m_format(format) { start(ec); }

      run_timer::run_timer( int places,
        system::error_code & ec  )
        : m_places(places), m_os(m_cout()) { start(ec); }
      run_timer::run_timer( std::ostream & os, int places,
        system::error_code & ec  )
        : m_places(places), m_os(os) { start(ec); }

      run_timer::run_timer( int places, const std::string & format,
        system::error_code & ec  )
        : m_places(places), m_os(m_cout()), m_format(format) { start(ec); }
      run_timer::run_timer( std::ostream & os, int places, const std::string & format,
        system::error_code & ec  )
        : m_places(places), m_os(os), m_format(format) { start(ec); }

    //  run_timer::report  -------------------------------------------------------------//

    void run_timer::report( system::error_code & ec )
    {
      m_reported = true;
      if ( m_format.empty() ) m_format = chrono_detail::default_format();

      process_times times;
      elapsed( times, ec );
      if (ec) return;

      if ( BOOST_CHRONO_IS_THROWS(ec) )
      {
        chrono_detail::show_time( times, m_format.c_str(), m_places, m_os );
      }
      else // non-throwing
      {
        try
        {
          chrono_detail::show_time( times, m_format.c_str(), m_places, m_os );
          if (!BOOST_CHRONO_IS_THROWS(ec))
          {
            ec.clear();
          }
        }

        catch (...) // eat any exceptions
        {
          BOOST_ASSERT( 0 && "error reporting not fully implemented yet" );
          if (BOOST_CHRONO_IS_THROWS(ec))
          {
              boost::throw_exception(
                      system::system_error(
                              errno,
                              BOOST_CHRONO_SYSTEM_CATEGORY,
                              "chrono::run_timer" ));
          }
          else
          {
            ec.assign(system::errc::success, BOOST_CHRONO_SYSTEM_CATEGORY);
          }
          }
      }
    }

    //  run_timer::test_report  --------------------------------------------------------//

    void run_timer::test_report( duration real_, duration user_, duration system_ )
    {
      if ( m_format.empty() ) m_format = chrono_detail::default_format();

      process_times times;
      times.real = real_;
      times.user = user_;
      times.system = system_;

      chrono_detail::show_time( times, m_format.c_str(), m_places, m_os );
    }

  } // namespace chrono
} // namespace boost

#endif

max_stars_repo_name: zigaosolin/Raytracer

max_issues_repo_name: zigaosolin/Raytracer

max_forks_repo_name: zigaosolin/Raytracer


text: #include <boost/spirit/include/qi_parse.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
#ifndef MAPNIK_TEXT_PROPERTIES_HPP
#define MAPNIK_TEXT_PROPERTIES_HPP

// mapnik
#include <mapnik/color.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/font_set.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/text/formatting/base.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/text/font_feature_settings.hpp>

// stl
#include <map>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/optional.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#pragma GCC diagnostic pop

namespace mapnik {

class feature_impl;
class text_layout;

namespace detail {

struct evaluated_format_properties
{
    std::string face_name;
    boost::optional<font_set> fontset;
    double text_size;
    double character_spacing;
    double line_spacing;
    double text_opacity;
    double halo_opacity;
    text_transform_e text_transform;
    color fill;
    color halo_fill;
    double halo_radius;
    font_feature_settings ff_settings;
};

struct evaluated_text_properties : util::noncopyable
{
    label_placement_e label_placement;
    double label_spacing;
    double label_position_tolerance;
    bool avoid_edges;
    double margin;
    double repeat_distance;
    double minimum_distance;
    double minimum_padding;
    double minimum_path_length;
    double max_char_angle_delta;
    bool allow_overlap;
    bool largest_bbox_only;
    text_upright_e upright;
    double grid_cell_width;
    double grid_cell_height;
};

}

using evaluated_text_properties_ptr = std::unique_ptr<detail::evaluated_text_properties>;

enum directions_e : std::uint8_t
{
    NORTH,
    EAST,
    SOUTH,
    WEST,
    NORTHEAST,
    SOUTHEAST,
    NORTHWEST,
    SOUTHWEST,
    EXACT_POSITION
};

using fontset_map = std::map<std::string, font_set>;

struct MAPNIK_DECL format_properties
{
    format_properties();
    void from_xml(xml_node const& sym, fontset_map const& fontsets, bool is_shield);
    void to_xml(boost::property_tree::ptree & node, bool explicit_defaults,
                format_properties const& dfl) const;
    // collect expressions
    void add_expressions(expression_set & output) const;

    std::string face_name;
    boost::optional<font_set> fontset;
    // expressions
    symbolizer_base::value_type text_size;
    symbolizer_base::value_type character_spacing;
    symbolizer_base::value_type line_spacing; //Largest total height (fontsize+line_spacing) per line is chosen
    symbolizer_base::value_type text_opacity;
    symbolizer_base::value_type halo_opacity;
    symbolizer_base::value_type fill;
    symbolizer_base::value_type halo_fill;
    symbolizer_base::value_type halo_radius;
    symbolizer_base::value_type text_transform;
    symbolizer_base::value_type ff_settings;
};

// Properties for building the layout of a single text placement
struct MAPNIK_DECL text_layout_properties
{
    text_layout_properties();

    // Load all values from XML ptree.
    void from_xml(xml_node const &sym, fontset_map const& fontsets);
    // Save all values to XML ptree (but does not create a new parent node!).
    void to_xml(boost::property_tree::ptree & node, bool explicit_defaults,
                text_layout_properties const& dfl) const;

    // Get a list of all expressions used in any placement.
    // This function is used to collect attributes.
    void add_expressions(expression_set & output) const;

    // per layout expressions
    symbolizer_base::value_type dx;
    symbolizer_base::value_type dy;
    symbolizer_base::value_type orientation;
    symbolizer_base::value_type text_ratio;
    symbolizer_base::value_type wrap_width;
    symbolizer_base::value_type wrap_char;
    symbolizer_base::value_type wrap_before;
    symbolizer_base::value_type repeat_wrap_char;
    symbolizer_base::value_type rotate_displacement;
    symbolizer_base::value_type halign;
    symbolizer_base::value_type jalign;
    symbolizer_base::value_type valign;
    directions_e dir = EXACT_POSITION;
};

struct text_properties_expressions
{
    symbolizer_base::value_type label_placement = enumeration_wrapper(POINT_PLACEMENT);
    symbolizer_base::value_type label_spacing = 0.0;
    symbolizer_base::value_type label_position_tolerance = 0.0;
    symbolizer_base::value_type avoid_edges = false;
    symbolizer_base::value_type margin = 0.0;
    symbolizer_base::value_type repeat_distance = 0.0;
    symbolizer_base::value_type minimum_distance = 0.0;
    symbolizer_base::value_type minimum_padding = 0.0;
    symbolizer_base::value_type minimum_path_length = 0.0;
    symbolizer_base::value_type max_char_angle_delta = 22.5;
    symbolizer_base::value_type allow_overlap = false;
    symbolizer_base::value_type largest_bbox_only = true;
    symbolizer_base::value_type upright = enumeration_wrapper(UPRIGHT_AUTO);
    symbolizer_base::value_type grid_cell_width = 0.0;
    symbolizer_base::value_type grid_cell_height = 0.0;
};

// Contains all text symbolizer properties which are not directly related to text formatting and layout.
struct MAPNIK_DECL text_symbolizer_properties
{
    text_symbolizer_properties();
    // Load only placement related values from XML ptree.
    void text_properties_from_xml(xml_node const& node);
    // Load all values from XML ptree.
    void from_xml(xml_node const& node, fontset_map const& fontsets, bool is_shield);
    // Save all values to XML ptree (but does not create a new parent node!).
    void to_xml(boost::property_tree::ptree & node, bool explicit_defaults,
                text_symbolizer_properties const& dfl) const;
    // Sets new format tree.
    void set_format_tree(formatting::node_ptr tree);
    // Get format tree.
    formatting::node_ptr format_tree() const;
    // Get a list of all expressions used in any placement.
    // This function is used to collect attributes.
    void add_expressions(expression_set & output) const;

    // Per symbolizer options
    // Expressions
    text_properties_expressions expressions;
    // Default values for text layouts
    text_layout_properties layout_defaults;
    // Default values for format_properties.
    format_properties format_defaults;

private:
    // A tree of formatting::nodes which contain text and formatting information.
    formatting::node_ptr tree_;
};

evaluated_text_properties_ptr evaluate_text_properties(text_symbolizer_properties const& text_prop, feature_impl const& feature, attributes const& attrs);

} //ns mapnik

#endif // MAPNIK_TEXT_PROPERTIES_HPP


text:
// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2014-2021, Oracle and/or its affiliates.

// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP

#include <algorithm>
#include <iterator>

#include <boost/core/addressof.hpp>

#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/intersects.hpp>

#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>

#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>

#include <boost/geometry/util/condition.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{

// compute segment-segment distance
template<typename Segment1, typename Segment2, typename Strategies>
class segment_to_segment
{
    typedef distance::strategy_t<Segment1, Segment2, Strategies> strategy_type;

public:
    typedef distance::return_t<Segment1, Segment2, Strategies> return_type;

    static inline return_type apply(Segment1 const& segment1, Segment2 const& segment2,
                                    Strategies const& strategies)
    {
        if (geometry::intersects(segment1, segment2, strategies))
        {
            return 0;
        }

        typename point_type<Segment1>::type p[2];
        detail::assign_point_from_index<0>(segment1, p[0]);
        detail::assign_point_from_index<1>(segment1, p[1]);

        typename point_type<Segment2>::type q[2];
        detail::assign_point_from_index<0>(segment2, q[0]);
        detail::assign_point_from_index<1>(segment2, q[1]);

        strategy_type const strategy = strategies.distance(segment1, segment2);

        auto const cstrategy = strategy::distance::services::get_comparable
                                <
                                    strategy_type
                                >::apply(strategy);

        distance::creturn_t<Segment1, Segment2, Strategies> d[4];
        d[0] = cstrategy.apply(q[0], p[0], p[1]);
        d[1] = cstrategy.apply(q[1], p[0], p[1]);
        d[2] = cstrategy.apply(p[0], q[0], q[1]);
        d[3] = cstrategy.apply(p[1], q[0], q[1]);

        std::size_t imin = std::distance(boost::addressof(d[0]),
                                         std::min_element(d, d + 4));

        if (BOOST_GEOMETRY_CONDITION(is_comparable<strategy_type>::value))
        {
            return d[imin];
        }

        switch (imin)
        {
        case 0:
            return strategy.apply(q[0], p[0], p[1]);
        case 1:
            return strategy.apply(q[1], p[0], p[1]);
        case 2:
            return strategy.apply(p[0], q[0], q[1]);
        default:
            return strategy.apply(p[1], q[0], q[1]);
        }
    }
};

}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

// segment-segment
template <typename Segment1, typename Segment2, typename Strategy>
struct distance
    <
        Segment1, Segment2, Strategy, segment_tag, segment_tag,
        strategy_tag_distance_point_segment, false
    >
    : detail::distance::segment_to_segment<Segment1, Segment2, Strategy>
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP

max_stars_repo_name: pranavgo/RRT

max_issues_repo_name: pranavgo/RRT

max_forks_repo_name: pranavgo/RRT


text:
#include <nano/lib/threading.hpp>
#include <nano/lib/timer.hpp>
#include <nano/node/blockprocessor.hpp>
#include <nano/node/election.hpp>
#include <nano/node/node.hpp>
#include <nano/node/websocket.hpp>
#include <nano/secure/store.hpp>

#include <boost/format.hpp>

std::chrono::milliseconds constexpr nano::block_processor::confirmation_request_delay;

nano::block_post_events::block_post_events (std::function<nano::read_transaction ()> && get_transaction_a) :
	get_transaction (std::move (get_transaction_a))
{
}

nano::block_post_events::~block_post_events ()
{
	debug_assert (get_transaction != nullptr);
	auto transaction (get_transaction ());
	for (auto const & i : events)
	{
		i (transaction);
	}
}

nano::block_processor::block_processor (nano::node & node_a, nano::write_database_queue & write_database_queue_a) :
	next_log (std::chrono::steady_clock::now ()),
	node (node_a),
	write_database_queue (write_database_queue_a),
	state_block_signature_verification (node.checker, node.ledger.network_params.ledger.epochs, node.config, node.logger, node.flags.block_processor_verification_size)
{
	state_block_signature_verification.blocks_verified_callback = [this] (std::deque<nano::unchecked_info> & items, std::vector<int> const & verifications, std::vector<nano::block_hash> const & hashes, std::vector<nano::signature> const & blocks_signatures) {
		this->process_verified_state_blocks (items, verifications, hashes, blocks_signatures);
	};
	state_block_signature_verification.transition_inactive_callback = [this] () {
		if (this->flushing)
		{
			{
				// Prevent a race with condition.wait in block_processor::flush
				nano::lock_guard<nano::mutex> guard (this->mutex);
			}
			this->condition.notify_all ();
		}
	};
	processing_thread = std::thread ([this] () {
		nano::thread_role::set (nano::thread_role::name::block_processing);
		this->process_blocks ();
	});
}

nano::block_processor::~block_processor ()
{
	stop ();
	if (processing_thread.joinable ())
	{
		processing_thread.join ();
	}
}

void nano::block_processor::stop ()
{
	{
		nano::lock_guard<nano::mutex> lock (mutex);
		stopped = true;
	}
	condition.notify_all ();
	state_block_signature_verification.stop ();
}

void nano::block_processor::flush ()
{
	node.checker.flush ();
	flushing = true;
	nano::unique_lock<nano::mutex> lock (mutex);
	while (!stopped && (have_blocks () || active || state_block_signature_verification.is_active ()))
	{
		condition.wait (lock);
	}
	flushing = false;
}

size_t nano::block_processor::size ()
{
	nano::unique_lock<nano::mutex> lock (mutex);
	return (blocks.size () + state_block_signature_verification.size () + forced.size ());
}

bool nano::block_processor::full ()
{
	return size () >= node.flags.block_processor_full_size;
}

bool nano::block_processor::half_full ()
{
	return size () >= node.flags.block_processor_full_size / 2;
}

void nano::block_processor::add (std::shared_ptr<nano::block> const & block_a, uint64_t origination)
{
	nano::unchecked_info info (block_a, 0, origination, nano::signature_verification::unknown);
	add (info);
}

void nano::block_processor::add (nano::unchecked_info const & info_a)
{
	debug_assert (!nano::work_validate_entry (*info_a.block));
	bool quarter_full (size () > node.flags.block_processor_full_size / 4);
	if (info_a.verified == nano::signature_verification::unknown && (info_a.block->type () == nano::block_type::state || info_a.block->type () == nano::block_type::open || !info_a.account.is_zero ()))
	{
		state_block_signature_verification.add (info_a);
	}
	else
	{
		{
			nano::lock_guard<nano::mutex> guard (mutex);
			blocks.emplace_back (info_a);
		}
		condition.notify_all ();
	}
}

void nano::block_processor::add_local (nano::unchecked_info const & info_a)
{
	release_assert (info_a.verified == nano::signature_verification::unknown && (info_a.block->type () == nano::block_type::state || !info_a.account.is_zero ()));
	debug_assert (!nano::work_validate_entry (*info_a.block));
	state_block_signature_verification.add (info_a);
}

void nano::block_processor::force (std::shared_ptr<nano::block> const & block_a)
{
	{
		nano::lock_guard<nano::mutex> lock (mutex);
		forced.push_back (block_a);
	}
	condition.notify_all ();
}

void nano::block_processor::wait_write ()
{
	nano::lock_guard<nano::mutex> lock (mutex);
	awaiting_write = true;
}

void nano::block_processor::process_blocks ()
{
	nano::unique_lock<nano::mutex> lock (mutex);
	while (!stopped)
	{
		if (have_blocks_ready ())
		{
			active = true;
			lock.unlock ();
			process_batch (lock);
			lock.lock ();
			active = false;
		}
		else
		{
			condition.notify_one ();
			condition.wait (lock);
		}
	}
}

bool nano::block_processor::should_log ()
{
	auto result (false);
	auto now (std::chrono::steady_clock::now ());
	if (next_log < now)
	{
		next_log = now + (node.config.logging.timing_logging () ? std::chrono::seconds (2) : std::chrono::seconds (15));
		result = true;
	}
	return result;
}

bool nano::block_processor::have_blocks_ready ()
{
	debug_assert (!mutex.try_lock ());
	return !blocks.empty () || !forced.empty ();
}

bool nano::block_processor::have_blocks ()
{
	debug_assert (!mutex.try_lock ());
	return have_blocks_ready () || state_block_signature_verification.size () != 0;
}

void nano::block_processor::process_verified_state_blocks (std::deque<nano::unchecked_info> & items, std::vector<int> const & verifications, std::vector<nano::block_hash> const & hashes, std::vector<nano::signature> const & blocks_signatures)
{
	{
		nano::unique_lock<nano::mutex> lk (mutex);
		for (auto i (0); i < verifications.size (); ++i)
		{
			debug_assert (verifications[i] == 1 || verifications[i] == 0);
			auto & item = items.front ();
			if (!item.block->link ().is_zero () && node.ledger.is_epoch_link (item.block->link ()))
			{
				// Epoch blocks
				if (verifications[i] == 1)
				{
					item.verified = nano::signature_verification::valid_epoch;
					blocks.emplace_back (std::move (item));
				}
				else
				{
					// Possible regular state blocks with epoch link (send subtype)
					item.verified = nano::signature_verification::unknown;
					blocks.emplace_back (std::move (item));
				}
			}
			else if (verifications[i] == 1)
			{
				// Non epoch blocks
				item.verified = nano::signature_verification::valid;
				blocks.emplace_back (std::move (item));
			}
			else
			{
				requeue_invalid (hashes[i], item);
			}
			items.pop_front ();
		}
	}
	condition.notify_all ();
}

void nano::block_processor::process_batch (nano::unique_lock<nano::mutex> & lock_a)
{
	auto scoped_write_guard = write_database_queue.wait (nano::writer::process_batch);
	block_post_events post_events ([&store = node.store] { return store.tx_begin_read (); });
	auto transaction (node.store.tx_begin_write ({ tables::accounts, tables::blocks, tables::frontiers, tables::pending, tables::unchecked }));
	nano::timer<std::chrono::milliseconds> timer_l;
	lock_a.lock ();
	timer_l.start ();
	// Processing blocks
	unsigned number_of_blocks_processed (0), number_of_forced_processed (0);
	auto deadline_reached = [&timer_l, deadline = node.config.block_processor_batch_max_time] { return timer_l.after_deadline (deadline); };
	auto processor_batch_reached = [&number_of_blocks_processed, max = node.flags.block_processor_batch_size] { return number_of_blocks_processed >= max; };
	auto store_batch_reached = [&number_of_blocks_processed, max = node.store.max_block_write_batch_num ()] { return number_of_blocks_processed >= max; };
	while (have_blocks_ready () && (!deadline_reached () || !processor_batch_reached ()) && !awaiting_write && !store_batch_reached ())
	{
		if ((blocks.size () + state_block_signature_verification.size () + forced.size () > 64) && should_log ())
		{
			node.logger.always_log (boost::str (boost::format ("%1% blocks (+ %2% state blocks) (+ %3% forced) in processing queue") % blocks.size () % state_block_signature_verification.size () % forced.size ()));
		}
		nano::unchecked_info info;
		nano::block_hash hash (0);
		bool force (false);
		if (forced.empty ())
		{
			info = blocks.front ();
			blocks.pop_front ();
			hash = info.block->hash ();
		}
		else
		{
			info = nano::unchecked_info (forced.front (), 0, nano::seconds_since_epoch (), nano::signature_verification::unknown);
			forced.pop_front ();
			hash = info.block->hash ();
			force = true;
			number_of_forced_processed++;
		}
		lock_a.unlock ();
		if (force)
		{
			auto successor (node.ledger.successor (transaction, info.block->qualified_root ()));
			if (successor != nullptr && successor->hash () != hash)
			{
				// Replace our block with the winner and roll back any dependent blocks
				if (node.config.logging.ledger_rollback_logging ())
				{
					node.logger.always_log (boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ()));
				}
				std::vector<std::shared_ptr<nano::block>> rollback_list;
				if (node.ledger.rollback (transaction, successor->hash (), rollback_list))
				{
					node.logger.always_log (nano::severity_level::error, boost::str (boost::format ("Failed to roll back %1% because it or a successor was confirmed") % successor->hash ().to_string ()));
				}
				else if (node.config.logging.ledger_rollback_logging ())
				{
					node.logger.always_log (boost::str (boost::format ("%1% blocks rolled back") % rollback_list.size ()));
				}
				// Deleting from votes cache, stop active transaction
				for (auto & i : rollback_list)
				{
					node.history.erase (i->root ());
					// Stop all rolled back active transactions except initial
					if (i->hash () != successor->hash ())
					{
						node.active.erase (*i);
					}
				}
			}
		}
		number_of_blocks_processed++;
		process_one (transaction, post_events, info, force);
		lock_a.lock ();
	}
	awaiting_write = false;
	lock_a.unlock ();

	if (node.config.logging.timing_logging () && number_of_blocks_processed != 0 && timer_l.stop () > std::chrono::milliseconds (100))
	{
		node.logger.always_log (boost::str (boost::format ("Processed %1% blocks (%2% blocks were forced) in %3% %4%") % number_of_blocks_processed % number_of_forced_processed % timer_l.value ().count () % timer_l.unit ()));
	}
}

void nano::block_processor::process_live (nano::transaction const & transaction_a, nano::block_hash const & hash_a, std::shared_ptr<nano::block> const & block_a, nano::process_return const & process_return_a, nano::block_origin const origin_a)
{
	// Start collecting quorum on block
	if (node.ledger.dependents_confirmed (transaction_a, *block_a))
	{
		auto account = block_a->account ().is_zero () ? block_a->sideband ().account : block_a->account ();
		node.scheduler.activate (account, transaction_a);
	}
	else
	{
		node.active.trigger_inactive_votes_cache_election (block_a);
	}

	// Announce block contents to the network
	if (origin_a == nano::block_origin::local)
	{
		node.network.flood_block_initial (block_a);
	}

	if (node.websocket_server && node.websocket_server->any_subscriber (nano::websocket::topic::new_unconfirmed_block))
	{
		node.websocket_server->broadcast (nano::websocket::message_builder ().new_block_arrived (*block_a));
	}
}

nano::process_return nano::block_processor::process_one (nano::write_transaction const & transaction_a, block_post_events & events_a, nano::unchecked_info info_a, const bool forced_a, nano::block_origin const origin_a)
{
	nano::process_return result;
	auto block (info_a.block);
	auto hash (block->hash ());
	result = node.ledger.process (transaction_a, *block, info_a.verified);
	switch (result.code)
	{
		case nano::process_result::progress:
		{
			release_assert (info_a.account.is_zero () || info_a.account == node.store.block.account_calculated (*block));
			if (node.config.logging.ledger_logging ())
			{
				std::string block_string;
				block->serialize_json (block_string, node.config.logging.single_line_record ());
				node.logger.try_log (boost::str (boost::format ("Processing block %1%: %2%") % hash.to_string () % block_string));
			}
			if ((info_a.modified > nano::seconds_since_epoch () - 300 && node.block_arrival.recent (hash)) || forced_a)
			{
				events_a.events.emplace_back ([this, hash, block = info_a.block, result, origin_a] (nano::transaction const & post_event_transaction_a) { process_live (post_event_transaction_a, hash, block, result, origin_a); });
			}
			queue_unchecked (transaction_a, hash);
			/* For send blocks check epoch open unchecked (gap pending).
			For state blocks check only send subtype and only if block epoch is not last epoch.
			If epoch is last, then pending entry shouldn't trigger same epoch open block for destination account. */
			if (block->type () == nano::block_type::send || (block->type () == nano::block_type::state && block->sideband ().details.is_send && std::underlying_type_t<nano::epoch> (block->sideband ().details.epoch) < std::underlying_type_t<nano::epoch> (nano::epoch::max)))
			{
				/* block->destination () for legacy send blocks
				block->link () for state blocks (send subtype) */
				queue_unchecked (transaction_a, block->destination ().is_zero () ? block->link () : block->destination ());
			}
			break;
		}
		case nano::process_result::gap_previous:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Gap previous for: %1%") % hash.to_string ()));
			}
			info_a.verified = result.verified;
			if (info_a.modified == 0)
			{
				info_a.modified = nano::seconds_since_epoch ();
			}

			nano::unchecked_key unchecked_key (block->previous (), hash);
			node.store.unchecked.put (transaction_a, unchecked_key, info_a);

			events_a.events.emplace_back ([this, hash] (nano::transaction const & /* unused */) { this->node.gap_cache.add (hash); });

			node.stats.inc (nano::stat::type::ledger, nano::stat::detail::gap_previous);
			break;
		}
		case nano::process_result::gap_source:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Gap source for: %1%") % hash.to_string ()));
			}
			info_a.verified = result.verified;
			if (info_a.modified == 0)
			{
				info_a.modified = nano::seconds_since_epoch ();
			}

			nano::unchecked_key unchecked_key (node.ledger.block_source (transaction_a, *(block)), hash);
			node.store.unchecked.put (transaction_a, unchecked_key, info_a);

			events_a.events.emplace_back ([this, hash] (nano::transaction const & /* unused */) { this->node.gap_cache.add (hash); });

			node.stats.inc (nano::stat::type::ledger, nano::stat::detail::gap_source);
			break;
		}
		case nano::process_result::gap_epoch_open_pending:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Gap pending entries for epoch open: %1%") % hash.to_string ()));
			}
			info_a.verified = result.verified;
			if (info_a.modified == 0)
			{
				info_a.modified = nano::seconds_since_epoch ();
			}

			nano::unchecked_key unchecked_key (block->account (), hash); // Specific unchecked key starting with epoch open block account public key
			node.store.unchecked.put (transaction_a, unchecked_key, info_a);

			node.stats.inc (nano::stat::type::ledger, nano::stat::detail::gap_source);
			break;
		}
		case nano::process_result::old:
		{
			if (node.config.logging.ledger_duplicate_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Old for: %1%") % hash.to_string ()));
			}
			node.stats.inc (nano::stat::type::ledger, nano::stat::detail::old);
			break;
		}
		case nano::process_result::bad_signature:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Bad signature for: %1%") % hash.to_string ()));
			}
			events_a.events.emplace_back ([this, hash, info_a] (nano::transaction const & /* unused */) { requeue_invalid (hash, info_a); });
			break;
		}
		case nano::process_result::negative_spend:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Negative spend for: %1%") % hash.to_string ()));
			}
			break;
		}
		case nano::process_result::unreceivable:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Unreceivable for: %1%") % hash.to_string ()));
			}
			break;
		}
		case nano::process_result::fork:
		{
			node.stats.inc (nano::stat::type::ledger, nano::stat::detail::fork);
			events_a.events.emplace_back ([this, block] (nano::transaction const &) { this->node.active.publish (block); });
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Fork for: %1% root: %2%") % hash.to_string () % block->root ().to_string ()));
			}
			break;
		}
		case nano::process_result::opened_burn_account:
		{
			node.logger.always_log (boost::str (boost::format ("*** Rejecting open block for burn account ***: %1%") % hash.to_string ()));
			break;
		}
		case nano::process_result::balance_mismatch:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Balance mismatch for: %1%") % hash.to_string ()));
			}
			break;
		}
		case nano::process_result::representative_mismatch:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Representative mismatch for: %1%") % hash.to_string ()));
			}
			break;
		}
		case nano::process_result::block_position:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Block %1% cannot follow predecessor %2%") % hash.to_string () % block->previous ().to_string ()));
			}
			break;
		}
		case nano::process_result::insufficient_work:
		{
			if (node.config.logging.ledger_logging ())
			{
				node.logger.try_log (boost::str (boost::format ("Insufficient work for %1% : %2% (difficulty %3%)") % hash.to_string () % nano::to_string_hex (block->block_work ()) % nano::to_string_hex (block->difficulty ())));
			}
			break;
		}
	}
	return result;
}

nano::process_return nano::block_processor::process_one (nano::write_transaction const & transaction_a, block_post_events & events_a, std::shared_ptr<nano::block> const & block_a)
{
	nano::unchecked_info info (block_a, block_a->account (), 0, nano::signature_verification::unknown);
	auto result (process_one (transaction_a, events_a, info));
	return result;
}

void nano::block_processor::queue_unchecked (nano::write_transaction const & transaction_a, nano::hash_or_account const & hash_or_account_a)
{
	auto unchecked_blocks (node.store.unchecked.get (transaction_a, hash_or_account_a.hash));
	for (auto & info : unchecked_blocks)
	{
		if (!node.flags.disable_block_processor_unchecked_deletion)
		{
			node.store.unchecked.del (transaction_a, nano::unchecked_key (hash_or_account_a, info.block->hash ()));
		}
		add (info);
	}
	node.gap_cache.erase (hash_or_account_a.hash);
}

void nano::block_processor::requeue_invalid (nano::block_hash const & hash_a, nano::unchecked_info const & info_a)
{
	debug_assert (hash_a == info_a.block->hash ());
	node.bootstrap_initiator.lazy_requeue (hash_a, info_a.block->previous (), info_a.confirmed);
}

std::unique_ptr<nano::container_info_component> nano::collect_container_info (block_processor & block_processor, std::string const & name)
{
	size_t blocks_count;
	size_t forced_count;

	{
		nano::lock_guard<nano::mutex> guard (block_processor.mutex);
		blocks_count = block_processor.blocks.size ();
		forced_count = block_processor.forced.size ();
	}

	auto composite = std::make_unique<container_info_composite> (name);
	composite->add_component (collect_container_info (block_processor.state_block_signature_verification, "state_block_signature_verification"));
	composite->add_component (std::make_unique<container_info_leaf> (container_info{ "blocks", blocks_count, sizeof (decltype (block_processor.blocks)::value_type) }));
	composite->add_component (std::make_unique<container_info_leaf> (container_info{ "forced", forced_count, sizeof (decltype (block_processor.forced)::value_type) }));
	return composite;
}

ext: cpp

max_stars_repo_name: starkmatt/nano-node

max_issues_repo_name: starkmatt/nano-node

max_forks_repo_name: starkmatt/nano-node


text:
#include "apriltag_ros/apriltag_detector_node.h"

#include <apriltag_msgs/ApriltagArrayStamped.h>
#include <boost/thread/lock_guard.hpp>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <sensor_msgs/image_encodings.h>

namespace apriltag_ros {

using namespace sensor_msgs;
using apriltag_msgs::ApriltagArrayStamped;

ApriltagDetectorNode::ApriltagDetectorNode(const ros::NodeHandle &pnh)
    : pnh_(pnh), it_(pnh_), cfg_server_(pnh) {
  cfg_server_.setCallback(
      boost::bind(&ApriltagDetectorNode::ConfigCb, this, _1, _2));

  // Setup connect callback
  auto connect_cb = boost::bind(&ApriltagDetectorNode::ConnectCb, this);
  boost::lock_guard<boost::mutex> lock(connect_mutex_);
  pub_tags_ =
      pnh_.advertise<ApriltagArrayStamped>("tags", 1, connect_cb, connect_cb);
  pub_disp_ = it_.advertise("disp", 1, connect_cb, connect_cb);
}

void ApriltagDetectorNode::ImageCb(const ImageConstPtr &image_msg) {
  const auto gray =
      cv_bridge::toCvShare(image_msg, image_encodings::MONO8)->image;

  // Detect
  auto apriltags = detector_->Detect(gray);

  // Publish apriltags
  auto apriltag_array_msg = boost::make_shared<ApriltagArrayStamped>();
  apriltag_array_msg->header = image_msg->header;
  apriltag_array_msg->apriltags = apriltags;
  pub_tags_.publish(apriltag_array_msg);

  // Publish detection image if needed
  if (pub_disp_.getNumSubscribers()) {
    cv::Mat disp;
    cv::cvtColor(gray, disp, CV_GRAY2BGR);
    DrawApriltags(disp, apriltags);
    cv_bridge::CvImage cv_img(image_msg->header, image_encodings::BGR8, disp);
    pub_disp_.publish(cv_img.toImageMsg());
  }
}

void ApriltagDetectorNode::ConfigCb(ConfigT &config, int level) {
  if (level < 0) {
    ROS_INFO("%s: %s", pnh_.getNamespace().c_str(),
             "Initializing reconfigure server");
  }
  if (level < 0 || config_.type != config.type ||
      config_.family != config.family) {
    // TODO: This maybe unsafe if someone changes the order in cfg
    detector_ = ApriltagDetector::Create(static_cast<DetectorType>(config.type),
                                         static_cast<TagFamily>(config.family));
  }
  detector_->set_black_border(config.black_border);
  detector_->set_decimate(config.decimate);
  detector_->set_nthreads(config.nthreads);

  // Save config
  config_ = config;
}

void ApriltagDetectorNode::ConnectCb() {
  boost::lock_guard<boost::mutex> lock(connect_mutex_);
  if (pub_tags_.getNumSubscribers() == 0 &&
      pub_disp_.getNumSubscribers() == 0) {
    // Shutting down if nobody subscribes
    ROS_DEBUG("%s: No subscribers, shutting down", pnh_.getNamespace().c_str());
    sub_image_.shutdown();
  } else if (!sub_image_) {
    ROS_DEBUG("%s: Resubscribing", pnh_.getNamespace().c_str());
    sub_image_ =
        it_.subscribe("image", 1, &ApriltagDetectorNode::ImageCb, this);
  }
}

} // namespace apriltag_ros

int main(int argc, char **argv) {
  ros::init(argc, argv, "apriltag_detector_node");
  ros::NodeHandle pnh("~");

  try {
    apriltag_ros::ApriltagDetectorNode node(pnh);
    ros::spin();
  } catch (const std::exception &e) {
    ROS_ERROR("%s: %s", pnh.getNamespace().c_str(), e.what());
  }
}


text:
// Copyright (c) 2008-2016 Emil Dotchevski and Reverge Studios, Inc.

// 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)

#ifndef UUID_FA3ED0DCA17911DEA6BBA09955D89593
#define UUID_FA3ED0DCA17911DEA6BBA09955D89593

#include <boost/qvm/assert.hpp>
#include <boost/qvm/deduce_mat.hpp>
#include <boost/qvm/detail/remove_const.hpp>
#include <boost/qvm/inline.hpp>

namespace boost {
namespace qvm {
template <class T, int R, int CR, int C> struct mat_traits<T[R][CR][C]> {
  static int const rows = 0;
  static int const cols = 0;
  typedef void scalar_type;
};

template <class T, int Rows, int Cols> struct mat_traits<T[Rows][Cols]> {
  typedef T this_matrix[Rows][Cols];
  typedef typename qvm_detail::remove_const<T>::type scalar_type;
  static int const rows = Rows;
  static int const cols = Cols;

  template <int Row, int Col>
  static BOOST_QVM_INLINE_CRITICAL scalar_type
  read_element(this_matrix const &x) {
    BOOST_QVM_STATIC_ASSERT(Row >= 0);
    BOOST_QVM_STATIC_ASSERT(Row < Rows);
    BOOST_QVM_STATIC_ASSERT(Col >= 0);
    BOOST_QVM_STATIC_ASSERT(Col < Cols);
    return x[Row][Col];
  }

  template <int Row, int Col>
  static BOOST_QVM_INLINE_CRITICAL scalar_type &write_element(this_matrix &x) {
    BOOST_QVM_STATIC_ASSERT(Row >= 0);
    BOOST_QVM_STATIC_ASSERT(Row < Rows);
    BOOST_QVM_STATIC_ASSERT(Col >= 0);
    BOOST_QVM_STATIC_ASSERT(Col < Cols);
    return x[Row][Col];
  }

  static BOOST_QVM_INLINE_CRITICAL scalar_type
  read_element_idx(int row, int col, this_matrix const &x) {
    BOOST_QVM_ASSERT(row >= 0);
    BOOST_QVM_ASSERT(row < Rows);
    BOOST_QVM_ASSERT(col >= 0);
    BOOST_QVM_ASSERT(col < Cols);
    return x[row][col];
  }

  static BOOST_QVM_INLINE_CRITICAL scalar_type &
  write_element_idx(int row, int col, this_matrix &x) {
    BOOST_QVM_ASSERT(row >= 0);
    BOOST_QVM_ASSERT(row < Rows);
    BOOST_QVM_ASSERT(col >= 0);
    BOOST_QVM_ASSERT(col < Cols);
    return x[row][col];
  }
};

template <class T, int Rows, int Cols, int R, int C>
struct deduce_mat<T[Rows][Cols], R, C> {
  typedef mat<T, R, C> type;
};

template <class T, int Rows, int Cols, int R, int C>
struct deduce_mat<T const[Rows][Cols], R, C> {
  typedef mat<T, R, C> type;
};

template <class T1, class T2, int Rows, int Cols, int R, int C>
struct deduce_mat2<T1[Rows][Cols], T2[Rows][Cols], R, C> {
  typedef mat<typename deduce_scalar<T1, T2>::type, R, C> type;
};

template <int Rows, int Cols, class T> T (&ptr_mref(T *ptr))[Rows][Cols] {
  return *reinterpret_cast<T(*)[Rows][Cols]>(ptr);
}
} // namespace qvm
} // namespace boost

#endif

max_stars_repo_name: henrywarhurst/matrix

max_issues_repo_name: henrywarhurst/matrix

max_forks_repo_name: henrywarhurst/matrix


text:
#include "cpp-gen.h"

#include <iostream>
#include <sstream>
#include <fstream>
#include <functional>
#include <boost/algorithm/string.hpp>

#include "exception.h"

namespace nnt {

std::string TensorsHeader::Generate() {
  const std::vector<Buffer>& buffers = model_.Buffers();
  std::string str_buf;

  for (const auto& buf : buffers) {
    if (buf.Data().size() > 0) {
      std::string str_vec = "";
      for (const auto& c : buf.Data()) {
        str_buf += c;
      }
    }
  }

  return str_buf;
}

std::string TensorsHeader::Assembler() {
  return Generate();
}

std::string ModelGen::Generate() {
  std::string str_init = "Init";
  return str_init;
}

std::string ModelGen::TensorTypeStr(TensorType type) {
  switch (type) {
    case TensorType::FLOAT32:
      return "ANEURALNETWORKS_TENSOR_FLOAT32";
      break;

    case TensorType::INT32:
      return "ANEURALNETWORKS_TENSOR_INT32";
      break;

    case TensorType::UINT8:
      return "ANEURALNETWORKS_TENSOR_QUANT8_ASYMM";
      break;

    default:
      FATAL("Tensor type not valid for Android NNAPI")
  }
}

std::string ModelGen::TensorCppTypeStr(TensorType type) {
  switch (type) {
    case TensorType::FLOAT32:
      return "FLOAT16";
      break;

    case TensorType::INT32:
      return "int32_t";
      break;

    case TensorType::UINT8:
      return "char";
      break;

    default:
      FATAL("Tensor type not valid for Android NNAPI")
  }
}

std::string ModelGen::TensorDim(const std::vector<int>& dim) {
  std::string str_out = "{";

  for (const auto& e : dim) {
    str_out += std::to_string(e) + ",";
  }

  str_out = str_out.substr(0, str_out.length() - 2);
  str_out += "}";

  return str_out;
}

float ModelGen::TensorQuantizationScale(const QuantizationParameters& q) {
  if (q.scale.size() > 0) {
    return q.scale[0];
  } else {
    return 0.0f;
  }
}

int ModelGen::TensorQuantizationZeroPoint(
    const QuantizationParameters& q) {
  if (q.zero_point.size() > 0) {
    return q.zero_point[0];
  } else {
    return 0;
  }
}

std::string ModelGen::GenerateTensorType(const Tensor& tensor, int count) {
  std::stringstream ss;
  std::string dimensions = TensorDim(tensor.shape());

  ss << "uint32_t dimensions_" << count << "[] = " << dimensions << ";\n";
  ss << "ANeuralNetworksOperandType operand_type_" << count << " {\n";

  std::string str_tensor_type = TensorTypeStr(tensor.tensor_type());
  int dimension_count = tensor.shape().size();

  float scale;
  int zero_point;

  if (tensor.HasQuantization()) {
    scale = TensorQuantizationScale(tensor.quantization());
    zero_point = TensorQuantizationZeroPoint(tensor.quantization());
  } else {
    scale = 0.0f;
    zero_point = 0;
  }

  ss << "  .type = " << str_tensor_type << ",\n";
  ss << "  .dimensionCount = " << dimension_count << ",\n";
  ss << "  .dimensions = " << "dimensions_" << count << ",\n";

  if (scale == 0) {
    ss << "  .scale = ." << scale << "f,\n";
  } else{
    ss << "  .scale = " << scale << "f,\n";
  }

  ss << "  .zeroPoint = " << zero_point << "\n";
  ss << "};\n\n";

  return ss.str();
}

std::string ModelGen::CheckStatus(const boost::format& msg) {
  std::stringstream ss;

  // nnapi always check the result of operation
  ss << "if (status != ANEURALNETWORKS_NO_ERROR) {\n";
  ss << "  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,\n";
  ss << "      \"" << boost::str(msg) << "\");\n";
  ss << "  return false;\n";
  ss << "}\n\n";

  return ss.str();
}

std::string ModelGen::GenerateTensorsCode() {
  Graph& graph = model_.graph();
  std::stringstream ss;

  int count = 0;
  for (const auto& tensor: graph.Tensors()) {
    // insert operand type
    ss << GenerateTensorType(tensor, count);

    // insert nnapi operand
    ss << "status = ANeuralNetworksModel_addOperand(model, ";
    ss << "&operand_type_" << count << ");\n";
    ss << CheckStatus(boost::format("ANeuralNetworksModel_addOperand failed"
        "for operand %1%")%count);

    size_t buf_size = tensor.buffer().Data().size();

    if (buf_size > 0) {
      // get tensor size
      ss << "tensor_size = " << buf_size << ";\n";

      // insert operand value
      ss << "status = ANeuralNetworksModel_setOperandValueFromMemory(model, ";
      ss << count << ", mem, offset, tensor_size);\n\n";
      ss << CheckStatus(boost::format(
          "ANeuralNetworksModel_setOperandValueFromMemory "
          "failed for operand %1%")%count);

      // calculates the offset
      ss << "offset += tensor_size;\n";
    }

    ++count;
  }

  count_operands_ = count;
  tensor_pos_ = graph.Tensors().size();

  return ss.str();
}

std::string ModelGen::GenerateOpInputs(const std::vector<int>& inputs,
    size_t num_params) {
  // inputs loop
  std::string str_in = "";

  // insert data params like conv filters params
  for (const auto& in_value : inputs) {
    str_in += " " + std::to_string(in_value) + ",";
  }

  // insert hiperparams like conv stride
  size_t tensor_start_pos = tensor_pos_;
  for (; tensor_pos_ < (tensor_start_pos + num_params); tensor_pos_++) {
    str_in += " " + std::to_string(tensor_pos_) + ",";
  }

  str_in = str_in.substr(0, str_in.length() - 1);
  return str_in;
}

std::string ModelGen::GenerateOpOutputs(const std::vector<int>& outputs) {
  // outputs loop
  std::string str_out = "";

  for (const auto& out_value : outputs) {
    str_out += " " + std::to_string(out_value) + ",";
  }

  str_out = str_out.substr(0, str_out.length() - 1);
  return str_out;
}

std::string ModelGen::OpTypeStr(BuiltinOperator op_type) {
  switch (op_type) {
    case BuiltinOperator::ADD:
      return "ANEURALNETWORKS_ADD";
      break;

    case BuiltinOperator::AVERAGE_POOL_2D:
      return "ANEURALNETWORKS_AVERAGE_POOL_2D";
      break;

    case BuiltinOperator::MAX_POOL_2D:
      return "ANEURALNETWORKS_MAX_POOL_2D";
      break;

    case BuiltinOperator::L2_POOL_2D:
      return "ANEURALNETWORKS_L2_POOL_2D";
      break;

    case BuiltinOperator::CONV_2D:
      return "ANEURALNETWORKS_CONV_2D";
      break;

    case BuiltinOperator::RELU:
      return "ANEURALNETWORKS_RELU";
      break;

    case BuiltinOperator::RELU6:
      return "ANEURALNETWORKS_RELU6";
      break;

    case BuiltinOperator::TANH:
      return "ANEURALNETWORKS_TANH";
      break;

    case BuiltinOperator::LOGISTIC:
      return "ANEURALNETWORKS_LOGISTIC";
      break;

    case BuiltinOperator::DEPTHWISE_CONV_2D:
      return "ANEURALNETWORKS_DEPTHWISE_CONV_2D";
      break;

    case BuiltinOperator::CONCATENATION:
      return "ANEURALNETWORKS_CONCATENATION";
      break;

    case BuiltinOperator::SOFTMAX:
      return "ANEURALNETWORKS_SOFTMAX";
      break;

    case BuiltinOperator::FULLY_CONNECTED:
      return "ANEURALNETWORKS_FULLY_CONNECTED";
      break;

    case BuiltinOperator::RESHAPE:
      return "ANEURALNETWORKS_RESHAPE";
      break;

    case BuiltinOperator::SPACE_TO_DEPTH:
      return "ANEURALNETWORKS_SPACE_TO_DEPTH";
      break;

    case BuiltinOperator::LSTM:
      return "ANEURALNETWORKS_LSTM";
      break;

    default:
      FATAL(boost::format("Not supported type on NNAPI"))
  }
}

std::string ModelGen::AddScalarInt32(int value) {
  std::stringstream ss;

  ss << "CHECK_ADD_SCALAR(AddScalarInt32(" << count_operands_ << ", "
     << value << "))\n";

  ++count_operands_;
  return ss.str();
}

std::string ModelGen::AddScalarFloat32(float value) {
  std::stringstream ss;

  ss << "CHECK_ADD_SCALAR(AddScalarFloat32(" << count_operands_ << ", "
     << value << "))\n";

  ++count_operands_;
  return ss.str();
}

std::tuple<size_t, std::string> ModelGen::OpParams(const Operator& op) {
  std::stringstream ss;
  size_t num_params = 0;

  auto check = [&op](BuiltinOptionsType type) {
    if (op.builtin_op().type != type) {
      FATAL(boost::format("Operator node type wrong"));
    }
  };

  switch (op.op_code().builtin_code) {
    case BuiltinOperator::ADD:
      ss << AddScalarInt32(0);
      num_params = 1;
      break;

    case BuiltinOperator::L2_POOL_2D:
    case BuiltinOperator::MAX_POOL_2D:
    case BuiltinOperator::AVERAGE_POOL_2D: {
      check(BuiltinOptionsType::Pool2DOptions);
      const Pool2DOptions& pool_options = static_cast<const Pool2DOptions&>(
          op.builtin_op());

      ss << AddScalarInt32(static_cast<int>(pool_options.padding));
      ss << AddScalarInt32(pool_options.stride_w);
      ss << AddScalarInt32(pool_options.stride_h);
      ss << AddScalarInt32(pool_options.filter_width);
      ss << AddScalarInt32(pool_options.filter_height);
      ss << AddScalarInt32(static_cast<int>(
          pool_options.fused_activation_function));
      num_params = 6;
      break;
    }

    case BuiltinOperator::CONV_2D: {
      check(BuiltinOptionsType::Conv2DOptions);
      const Conv2DOptions& conv_options = static_cast<const Conv2DOptions&>(
          op.builtin_op());

      ss << AddScalarInt32(static_cast<int>(conv_options.padding));
      ss << AddScalarInt32(conv_options.stride_w);
      ss << AddScalarInt32(conv_options.stride_h);
      ss << AddScalarInt32(static_cast<int>(
          conv_options.fused_activation_function));
      num_params = 4;
      break;
    }

    case BuiltinOperator::DEPTHWISE_CONV_2D: {
      check(BuiltinOptionsType::DepthwiseConv2DOptions);
      const DepthwiseConv2DOptions& dept_conv_options =
          static_cast<const DepthwiseConv2DOptions&>(op.builtin_op());

      ss << AddScalarInt32(static_cast<int>(dept_conv_options.padding));
      ss << AddScalarInt32(dept_conv_options.stride_w);
      ss << AddScalarInt32(dept_conv_options.stride_h);
      ss << AddScalarInt32(dept_conv_options.depth_multiplier);
      ss << AddScalarInt32(static_cast<int>(
          dept_conv_options.fused_activation_function));
      num_params = 5;
      break;
    }

    case BuiltinOperator::FULLY_CONNECTED: {
      check(BuiltinOptionsType::FullyConnectedOptions);
      const FullyConnectedOptions& fully_con_options =
          static_cast<const FullyConnectedOptions&>(op.builtin_op());

      ss << AddScalarInt32(static_cast<int>(
          fully_con_options.fused_activation_function));
      num_params = 1;
      break;
    }

    case BuiltinOperator::CONCATENATION: {
      check(BuiltinOptionsType::ConcatenationOptions);
      const ConcatenationOptions& concat_options =
          static_cast<const ConcatenationOptions&>(op.builtin_op());

      ss << AddScalarInt32(concat_options.axis);
      ss << AddScalarInt32(static_cast<int>(
          concat_options.fused_activation_function));
      num_params = 2;
      break;
    }

    case BuiltinOperator::SOFTMAX: {
      check(BuiltinOptionsType::SoftmaxOptions);
      const SoftmaxOptions& softmax_options =
          static_cast<const SoftmaxOptions&>(op.builtin_op());

      ss << AddScalarFloat32(softmax_options.beta);
      num_params = 1;
      break;
    }

    case BuiltinOperator::SPACE_TO_DEPTH: {
      check(BuiltinOptionsType::SpaceToDepthOptions);
      const SpaceToDepthOptions& space2depth_options =
          static_cast<const SpaceToDepthOptions&>(op.builtin_op());

      ss << AddScalarInt32(space2depth_options.block_size);
      num_params = 1;
      break;
    }

    case BuiltinOperator::LSTM: {
      check(BuiltinOptionsType::LSTMOptions);
      // TODO: Check better on TfLite how lstm parametes is filled
      const LSTMOptions& lstm_options = static_cast<const LSTMOptions&>(
          op.builtin_op());

      ss << AddScalarInt32(static_cast<int>(
          lstm_options.fused_activation_function));
      ss << AddScalarInt32(lstm_options.cell_clip);
      ss << AddScalarInt32(lstm_options.proj_clip);
      num_params = 3;
      break;
    }

    default:
      num_params = 0;
  }

  return std::tuple<size_t, std::string>(num_params, ss.str());
}

std::string ModelGen::GenerateOpCode() {
  Graph& graph = model_.graph();
  std::stringstream ss;

  int count = 0;
  for (const auto& op: graph.Operators()) {
    size_t num_params;
    std::string str_params;
    std::tie(num_params, str_params) = OpParams(op);
    ss << str_params << "\n";
    ss << "uint32_t input_operands_" << count << "[] = { ";
    ss << GenerateOpInputs(op.inputs(), num_params) << " };\n";

    ss << "uint32_t output_operands_" << count << "[] = {";
    ss << GenerateOpOutputs(op.outputs()) << " };\n\n";

    ss << "status = ANeuralNetworksModel_addOperation(model, ";
    ss << OpTypeStr(op.op_code().builtin_code) << ", sizeof(input_operands_" ;
    ss << count <<"), input_operands_" << count << ", ";
    ss << "sizeof(output_operands_" << count << "), ";
    ss << "output_operands_" << count << ");\n";

    ss << CheckStatus(boost::format(
        "ANeuralNetworksModel_addOperation failed for operation %1%")%count);

    ++count;
  }

  return ss.str();
}

std::string ModelGen::GenerateInputsAndOutputs() {
  Graph& graph = model_.graph();
  std::stringstream ss;

  size_t num_inputs = graph.Inputs().size();;
  ss << "uint32_t input_indexes[" << num_inputs << "] = {";

  std::string str_input;
  for (int i : graph.Inputs()) {
    str_input += " " + std::to_string(i) + ",";
  }

  str_input = str_input.substr(0, str_input.length() - 1);
  ss << str_input << " };\n";

  size_t num_outputs = graph.Outputs().size();
  ss << "uint32_t output_indexes[" << num_outputs << "] = {";

  std::string str_output;
  for (int i : graph.Outputs()) {
    str_output += " " + std::to_string(i) + ",";
  }

  str_output = str_output.substr(0, str_output.length() - 1);
  ss << str_output << " };\n";

  ss << "ANeuralNetworksModel_identifyInputsAndOutputs(model, "
     << num_inputs << ", input_indexes, " << num_outputs
     << ", output_indexes);\n";

  return ss.str();
}

std::string TensorType(const Tensor& tensor) {
  switch (tensor.tensor_type()) {
    case TensorType::FLOAT32:
      return "float32_t";
      break;

    case TensorType::INT32:
      return "int32_t";
      break;

    case TensorType::UINT8:
      return "int8_t";
      break;

    default:
      FATAL("Tensor type not valid for Android NNAPI")
  }
}

int ModelGen::TensorSize(const Tensor& tensor) {
  int size = 1;
  for (int shape_i : tensor.shape()) {
    size *= shape_i;

    if (tensor.tensor_type() == TensorType::FLOAT32 ||
        tensor.tensor_type() == TensorType::INT32) {
      size *= 4;
    }
  }

  return size;
}

std::string ModelGen::GenerateInputFunctions() {
  Graph& graph = model_.graph();
  std::string str_input;

  str_input += "bool SetInput(const int8_t *buffer) {\n";

  int start = 0;
  for (int i : graph.Inputs()) {
    const Tensor& tensor = graph.Tensors()[i];
    int size = TensorSize(tensor);

    str_input += "  int status = ANeuralNetworksExecution_setInput(run, " +
        std::to_string(i) + ", NULL, &buffer[" + std::to_string(start) +
        "], " + std::to_string(size) + ");\n";

    str_input += CheckStatus(boost::format(
        "ANeuralNetworksExecution_setInput failed"));

    start += size;
  }

  str_input += "  return true;\n}\n\n";

  return str_input;
}

std::string ModelGen::GenerateOutputFunctions() {
  Graph& graph = model_.graph();
  std::string str_output;

  str_output += "bool SetOutput(int8_t *buffer) {\n";

  int start = 0;
  for (int i : graph.Outputs()) {
    const Tensor& tensor = graph.Tensors()[i];
    int size = TensorSize(tensor);

    str_output += "  int status = ANeuralNetworksExecution_setOutput(run, " +
        std::to_string(i) + ", NULL, &buffer[" + std::to_string(start) +
        "], " + std::to_string(size) + ");\n";

    str_output += CheckStatus(boost::format(
        "ANeuralNetworksExecution_setOutput failed"));

    start += size;
  }

  str_output += "  return true;\n}\n\n";

  return str_output;
}

std::string ModelGen::GenerateHeader() {
  std::string str =
#include "templates/top_nn_cc.tpl"
  ;
  return str;
}

std::string ModelGen::Assembler() {
  std::string code;
  code = GenerateHeader();
  code += GenerateTensorsCode();
  code += GenerateOpCode();
  code += GenerateInputsAndOutputs();

  // close model function
  code += "return true;\n}\n\n";

  code += GenerateInputFunctions();
  code += GenerateOutputFunctions();

  // close namespace
  code += "\n}\n\n";

  return code;
}

std::string ModelGenHeader::GenerateHeader() {
  std::string str =
  #include "templates/top_nn_h.tpl"
  ;
  return str;
}

std::string ModelGenHeader::Assembler() {
  std::string str = GenerateHeader();
  str += "}";

  return str;
}

template<class Fn>
int ModelGenJni::TotalSize(Fn&& fn) {
  Graph& graph = model_.graph();
  int total_size = 0;

  for (int i : fn()) {
    int size = 1;
    const Tensor& tensor = graph.Tensors()[i];

    for (int shape_i : tensor.shape()) {
      size *= shape_i;

      if (tensor.tensor_type() == TensorType::FLOAT32 ||
          tensor.tensor_type() == TensorType::INT32) {
        size *= 4;
      }
    }
    total_size += size;
  }

  return total_size;
}

std::string ModelGenJni::GenerateJni() {
  std::string str =
#include "templates/jni.tpl"
  ;

  Graph& graph = model_.graph();

  auto fn_in = std::bind(&Graph::Inputs, &graph);
  int total_input_size = TotalSize(fn_in);

  auto fn_out = std::bind(&Graph::Outputs, &graph);
  int total_output_size = TotalSize(fn_out);

  boost::replace_all(str, "@TOTAL_INPUT_SIZE",
      std::to_string(total_input_size));
  boost::replace_all(str, "@TOTAL_OUTPUT_SIZE",
      std::to_string(total_output_size));
  boost::replace_all(str, "@JAVA_PACKAGE", java_package_);

  return str;
}

std::string ModelGenJni::Assembler() {
  boost::replace_all(java_package_, ".", "_");
  std::string str = GenerateJni();
  return str;
}

void CppGen::GenFiles(const boost::filesystem::path& path,
    const std::string& java_path) {
  GenTensorsDataFile(path);
  GenCppFile(path);
  GenHFile(path);
  GenJniFile(path, java_path);
}

void CppGen::GenTensorsDataFile(const boost::filesystem::path& path) {
  const boost::filesystem::path& fname("weights_biases.bin");
  std::string str_path = (path / fname).string();
  std::ofstream tensors_file(str_path,
      std::ofstream::out | std::ofstream::binary);

  if (!tensors_file.is_open()) {
    FATAL(boost::format("Fail on create weights_biases.bin file on: %1%")
        %str_path)
  }

  TensorsHeader tensor_header(model_);
  std::string buf = tensor_header.Assembler();
  tensors_file.write(buf.c_str(), buf.length());
  tensors_file.close();

  std::cout << "File: " << str_path << " generated\n";
}

void CppGen::GenCppFile(const boost::filesystem::path& path) {
  const boost::filesystem::path& fname("nn.cc");
  std::string str_path = (path / fname).string();
  std::ofstream cc_file(str_path, std::ofstream::out | std::ofstream::binary);

  if (!cc_file.is_open()) {
    FATAL("Fail on create nn.cc file")
  }

  ModelGen model(model_);
  std::string code = model.Assembler();
  cc_file.write(code.c_str(), code.length());
  cc_file.close();

  std::cout << "File: " << str_path << " generated\n";
}

void CppGen::GenHFile(const boost::filesystem::path& path) {
  const boost::filesystem::path& fname("nn.h");
  std::string str_path = (path / fname).string();

  std::ofstream cc_file(str_path, std::ofstream::out | std::ofstream::binary);

  if (!cc_file.is_open()) {
    FATAL("Fail on create nn.h file")
  }

  ModelGenHeader model(model_);
  std::string code = model.Assembler();
  cc_file.write(code.c_str(), code.length());
  cc_file.close();

  std::cout << "File: " << str_path << " generated\n";
}

void CppGen::GenJniFile(const boost::filesystem::path& path,
    const std::string& java_package) {
  const boost::filesystem::path& fname("jni.cc");
  std::string str_path = (path / fname).string();
  std::ofstream jni_file(str_path, std::ofstream::out | std::ofstream::binary);

  if (!jni_file.is_open()) {
    FATAL("Fail on create nn.h file")
  }

  ModelGenJni model(model_, java_package);
  std::string code = model.Assembler();
  jni_file.write(code.c_str(), code.length());
  jni_file.close();

  std::cout << "File: " << str_path << " generated\n";
}

}

ext: cc