text:
// This **asynchronous** synthetic multi-thread scheduler will create
// "fake" task ids, and query the DB to find a worker.  There won't be actual
// workers or load generators.
// The goal is to benchmark the basic latency, throughput, and scalability of
// parallel schedulers.

#include <getopt.h>
#include <atomic>
#include <boost/shared_ptr.hpp>
#include <string>
#include <thread>
#include <unordered_set>
#include <vector>

#include "BenchmarkUtil.h"
#include "PartitionedFIFOScheduler.h"
#include "PartitionedLocalFIFOScheduler.h"
#include "PartitionedFIFOTaskScheduler.h"
#include "PartitionedScanTask.h"
#include "PushFIFOScheduler.h"
#include "RandomGenerator.h"
#include "SinglePartitionedFIFOTaskScheduler.h"
#include "SparkScheduler.h"
#include "VoltdbSchedulerUtil.h"
#include "voltdb-client-cpp/include/Client.h"
#include "voltdb-client-cpp/include/ProcedureCallback.hpp"
#include "voltdb-client-cpp/include/Row.hpp"
#include "voltdb-client-cpp/include/Table.h"
#include "voltdb-client-cpp/include/TableIterator.h"

// Number of schedulers and workers
static int numSchedulers = 1;
static int numWorkers = 1;
static int numTasks = 8;

// Number of worker/task partitions, not VoltDB partitions.
static int partitions = 8;

// Assume each worker has infinite capacity.
static int workerCapacity = (1L << 27);

// Probability to do multi-partition transaction
static float probMultiTx = 0.0;

// Power multiplier for the latency array.
// We can record at most 2^26 = 67108864 latencies
static const int kArrayExp = 26;
static const size_t kMaxEntries = (1L << kArrayExp);

// Report latency/throughput stats every interval.
static int measureIntervalMsec = 2000;  // 2sec in ms.

// Total benchmarking time.
static int totalExecTimeMsec = 10000;  // 10sec in ms.

// Requests per second, must be greater than 0.
static double reqPerSec = 100;
static double reqPerSecThread = 100;  // Request rate per thread.

// Types of random distributions.
static const std::string kNoDist = "none";
static const std::string kFixed = "fixed";
static const std::string kPoisson = "poisson";
static const std::string kUniform = "uniform";
static const std::unordered_set<std::string> kDists = {kNoDist, kFixed,
                                                       kPoisson, kUniform};
static std::string reqDist = kNoDist;  // by default, send as fast as possible.

static bool mainFinished = false;  // Control whether to stop the experiment.

// Record latencies in a single big array.
static double* schedLatencies;
// The current index of the schedLatencies array.
static std::atomic<uint32_t> schedLatsArrayIndex;
// The indices for each interval boundary (add a new one every interval).
static std::vector<uint32_t> schedIndices;
// Timestamp of each interval starts, in userc.
static std::vector<uint64_t> timeStampsUsec;

// Synthetic username, passwd.
static const std::string kTestUser = "testuser";
static const std::string kTestPwd = "testpassword";

// Type of scheduler algorithm
// TODO: add more types here.
static const std::string kFifoAlgo = "fifo";
static const std::string kFifoLocalAlgo = "fifo-local";
static const std::string kSinglePartitionedFifoTaskAlgo =
    "single-partitioned-fifo-task";

// TODO: currently only FIFO supports async. Will add more.
static const std::unordered_set<std::string> kAlgorithms = {kFifoAlgo, kFifoLocalAlgo, kSinglePartitionedFifoTaskAlgo};
static std::string scheduleAlgo = kFifoAlgo;

// Max outstanding requests per thread.
static int maxOutstanding = 1;

// If true, truncate tables after execution.
static bool cleanDB = false;

// If true, do not setup tables before execution. Otherwise, setup the table.
static bool noSetupDB = false;

// If true, output avg cpu usage for each benchmark
static bool outputCpuUsage = false;
static const std::string cpuUsageTxtLog = "cpu_usage.txt";
static const std::string cpuUsageCsvResults = "cpu_usage.csv";

// Callback for async client.
// Note: VoltDB C++ client is single threaded; thus the callback is executed on
// the same thread as the one sending requests. Therefore, the sender thread
// needs to periodically call "runOnce()" to enter the event loop and process
// callbacks.
class SchedulerCallback : public voltdb::ProcedureCallback {
public:
  SchedulerCallback(int64_t maxOutCnt)
      : outCnt_(0), endThresh_(maxOutCnt / 2) {}

  bool callback(voltdb::InvocationResponse response) throw(voltdb::Exception) {
    bool retVal = false;
    if (response.failure()) {
      std::cerr << "Failed to execute!\n";
      std::cerr << response.toString();
      exit(1);
    }
    auto aryIndex = schedLatsArrayIndex.fetch_add(1);
    if (aryIndex >= kMaxEntries) {
      std::cerr << "Array schedLatencies out of bounds: " << aryIndex
                << std::endl;
      exit(1);
    }

    // Convert to microseconds.
    // NOTE: the clusterRoundTripTime is the VoltDB internal server side
    // latency, and in millisecond granularity. Thus, it is normal to have
    // "zero" latency here.
    // TODO: figure out a better way to measure async client side latency.
    double latency = (double)response.clusterRoundTripTime() * 1000.0;
    schedLatencies[aryIndex] = latency;
    std::vector<voltdb::Table> results = response.results();
    voltdb::Row row = results[0].iterator().next();
    DbosId selectedWorker = row.getInt64(0);
    assert(selectedWorker >= 0);

    outCnt_--;
    if (outCnt_ <= endThresh_) {
      // If reaches the threshold, break the event loop and return to
      // scheduling. Otherwise, the event loop would continue to process all
      // responses.
      // TODO: find a better heuristic to end the loop.
      retVal = true;
    }
    return retVal;
  }

  int64_t outCnt_;

private:
  int64_t endThresh_;  // threshold to end the event loop.
};

/*
 * Return a constructed scheduler instance based on algorithm.
 */
static VoltdbSchedulerUtil* constructScheduler(voltdb::Client* voltdbClient,
                                               const std::string& serverAddr,
                                               const std::string& algo) {
  VoltdbSchedulerUtil* scheduler = nullptr;
  if (algo == kFifoAlgo) {
    scheduler = new PartitionedFIFOScheduler(
        voltdbClient, serverAddr, partitions, workerCapacity, numWorkers);
  } else if (algo == kFifoLocalAlgo) {
    scheduler = new PartitionedLocalFIFOScheduler(
        voltdbClient, serverAddr, partitions, workerCapacity, numWorkers);
  } else if (algo == kSinglePartitionedFifoTaskAlgo) {
    scheduler = new SinglePartitionedFIFOTaskScheduler(
        voltdbClient, serverAddr, partitions, numTasks, workerCapacity,
        numWorkers, 0.0);
  } else {
    std::cerr << "Unsupported scheduler algorithm: " << algo << "\n";
  }

  return scheduler;
}

/*
 * Scheduler thread.
 * For now, it will simply select a worker and decrease it's capacity.
 * We will need to add worker (consumer) to mark tasks finished.
 */
static void SchedulerThread(const int schedulerId,
                            const std::string& serverAddr) {
  // Create a local VoltDB client.
  voltdb::Client voltdbClient =
      VoltdbSchedulerUtil::createVoltdbClient(kTestUser, kTestPwd);

  VoltdbSchedulerUtil* scheduler =
      constructScheduler(&voltdbClient, serverAddr, scheduleAlgo);
  assert(scheduler != nullptr);
  std::cout << "Scheduler: " << schedulerId << " started\n";
  boost::shared_ptr<SchedulerCallback> callback(
      new SchedulerCallback(maxOutstanding));
  callback->outCnt_ = 0;
  // Inter-arrival latency generator.
  Generator* iaGen = nullptr;
  if (reqDist == kFixed) {
    iaGen = new Fixed(reqPerSecThread);
  } else if (reqDist == kPoisson) {
    iaGen = new Poisson(reqPerSecThread);
  } else if (reqDist == kUniform) {
    iaGen = new Uniform(reqPerSecThread);
  } else if (reqDist == kNoDist) {
    std::cerr << "sending as fast as possible.\n";
  } else {
    std::cerr << "Unsupported distribution: " << reqDist << "\n";
    exit(-1);
  }

  // If No distribution, send out as fast as possible, and allow batching.
  if (reqDist == kNoDist) {
    do {
      // Make async scheduling decisions here.
      auto status = scheduler->asyncSchedule(callback);
      assert(status);
      callback->outCnt_++;
      if (callback->outCnt_ >= maxOutstanding) {
        // Run the event loop once; return immediately if no responses. It will
        // process callbacks until the event loop finished or callback returns
        // true.
        // TODO: either find a better heuristic, or run callbacks on a separate
        // thread.
        voltdbClient.runOnce();
        continue;
      }

      if (callback->outCnt_ > maxOutstanding / 2) {
        // Heuristic to process responses in time.
        // TODO: either find a better heuristic, or run callbacks on a separate
        // thread.
        voltdbClient.runOnce();
        continue;
      }

    } while (!mainFinished);

  } else {
    // Otherwise, enter the control loop, execute the query without batching.
    uint64_t currTime = BenchmarkUtil::getCurrTimeUsec();
    uint64_t nextTime = currTime + (uint64_t)(iaGen->generate() * 1000 * 1000);
    do {
      if (nextTime <= currTime) {
        // Make async scheduling decisions here.
        auto status = scheduler->asyncSchedule(callback);
        assert(status);
        callback->outCnt_++;
        // Run the event loop once; return immediately if no responses.
        voltdbClient.runOnce();

        // Update nextTime.
        nextTime = nextTime + (uint64_t)(iaGen->generate() * 1000 * 1000);
      } else {
        // Avoid busy loop. We also don't want to directly sleep interval time
        // because that may cause high latency or cannot finish the experiment
        // in time.
        uint64_t delay = (nextTime - currTime);
        delay = delay > 5 ? 5 : delay;
        std::this_thread::sleep_for(std::chrono::microseconds(delay));
      }
      currTime = BenchmarkUtil::getCurrTimeUsec();

    } while (!mainFinished);
  }

  // Give outstanding requests time to finish.
  while (!voltdbClient.drain()) {}

  // Clean up
  delete scheduler;
  if (iaGen != nullptr) { delete iaGen; }
  return;
}

/*
 * Actually run the benchmark.
 */
static bool runBenchmark(const std::string& serverAddr,
                         const std::string& outputFile) {
  mainFinished = false;

  std::vector<std::thread*> schedulerThreads;  // Parallel schedulers.

  // Initialize measurement arrays.
  uint64_t currTime = BenchmarkUtil::getCurrTimeUsec();
  timeStampsUsec.push_back(currTime);
  schedLatencies = new double[kMaxEntries];
  memset(schedLatencies, 0, kMaxEntries * sizeof(double));
  schedLatsArrayIndex.store(0);
  schedIndices.push_back(0);

  // Start scheduler threads.
  for (int i = 0; i < numSchedulers; ++i) {
    schedulerThreads.push_back(
        new std::thread(&SchedulerThread, i, serverAddr));
  }

  std::string cmd;
  if (outputCpuUsage) {  // Output CPU usage stats from `top` to a .txt file
    std::string log_header_cmd = "echo | date > " + cpuUsageTxtLog;
    std::system(log_header_cmd.c_str());
    // Discard first top output and only save the second one
    cmd = "top -b -n 2 -d " + std::to_string((float) measureIntervalMsec / 1000.0) +
              " | awk '/top - /{i++}i>=2'" + ">> "+ cpuUsageTxtLog + " &";
  }

  currTime = BenchmarkUtil::getCurrTimeUsec();
  uint64_t endTime = currTime + (totalExecTimeMsec * 1000);
  do {
    if (outputCpuUsage) std::system(cmd.c_str());
    std::this_thread::sleep_for(std::chrono::milliseconds(measureIntervalMsec));
    std::cerr << "runBenchmark recording performance...\n";
    currTime = BenchmarkUtil::getCurrTimeUsec();
    schedIndices.push_back(schedLatsArrayIndex.load());
    timeStampsUsec.push_back(currTime);
  } while (currTime < endTime);

  mainFinished = true;
  for (int i = 0; i < numSchedulers; ++i) {
    schedulerThreads[i]->join();
    delete schedulerThreads[i];
  }

  // Processing the results.
  std::cerr << "Post processing results...\n";
  bool res = BenchmarkUtil::processResults(
      schedLatencies, schedIndices, timeStampsUsec, outputFile, scheduleAlgo, outputCpuUsage);
  if (!res) {
    std::cerr << "[Warning]: failed to write results to " << outputFile << "\n";
  }

  // Clean up.
  delete[] schedLatencies;
  schedLatencies = nullptr;
  timeStampsUsec.clear();
  return true;
}

/*
 * Setup database.
 */
static bool setup(const std::string& serverAddr) {
  // Create a local VoltDB client.
  voltdb::Client voltdbClient =
      VoltdbSchedulerUtil::createVoltdbClient(kTestUser, kTestPwd);

  VoltdbSchedulerUtil* scheduler =
      constructScheduler(&voltdbClient, serverAddr, scheduleAlgo);
  assert(scheduler != nullptr);
  bool res = scheduler->setup();
  delete scheduler;
  return res;
}

/*
 * Cleanup database.
 */
static bool teardown(const std::string& serverAddr) {
  // Create a local VoltDB client.
  voltdb::Client voltdbClient =
      VoltdbSchedulerUtil::createVoltdbClient(kTestUser, kTestPwd);

  VoltdbSchedulerUtil* scheduler =
      constructScheduler(&voltdbClient, serverAddr, scheduleAlgo);
  assert(scheduler != nullptr);
  bool res = scheduler->teardown();
  delete scheduler;
  return res;
}

static void Usage(char** argv, const std::string& msg = "") {
  if (!msg.empty()) { std::cerr << "ERROR: " << msg << std::endl; }
  std::cerr << "Usage: " << argv[0] << "[options]\n";
  std::cerr << "\t-h: show this message\n";
  std::cerr << "\t-x: truncate DB tables after execution.\n";
  std::cerr << "\t-X: NOT setup DB tables before execution.\n";
  std::cerr << "\t-c: output log of avg cpu usage.\n";
  std::cerr << "\t-o <output log file path>: default "
            << "synthetic_scheduler_results.csv\n";
  std::cerr << "\t-s <comma-separated list of servers>: default 'localhost'\n";
  std::cerr << "\t-i <measurement interval>: default " << measureIntervalMsec
            << " msec\n";
  std::cerr << "\t-t <total execution time>: default " << totalExecTimeMsec
            << " msec\n";
  std::cerr << "\t-N <number of parallel schedulers (threads)>: default "
            << numSchedulers << "\n";
  std::cerr << "\t-W <number of workers (#rows in table)>: default "
            << numWorkers << "\n";
  std::cerr << "\t-C <worker capacity>: default " << workerCapacity << "\n";
  std::cerr << "\t-T <number of tasks>: default " << numTasks << "\n";
  std::cerr << "\t-P <partitions>: default " << partitions << "\n";
  std::cerr << "\t-R <request rate>: default " << reqPerSec << "\n";
  std::cerr << "\t-D <request distribution>: default " << reqDist
            << " (options: ";
  for (auto&& it : kDists) { std::cerr << it << " "; }
  std::cerr << ")\n";
  // Max outstanding requests: if reaches this threshold, runs the event loop
  // once to process potential responses.
  std::cerr << "\t-m <max outstanding requests>: default " << maxOutstanding
            << "\n";
  std::cerr
      << "\t-p <probability of multi-partition transaction> (0-1.0): default "
      << probMultiTx << "\n";
  // Print all options here.
  std::cerr << "\t-A <scheduler algorithm (options: ";
  for (auto&& it : kAlgorithms) { std::cerr << it << " "; }
  std::cerr << ")> default " << scheduleAlgo << "\n";

  std::cerr << std::endl;
  exit(1);
}

int main(int argc, char** argv) {
  std::string serverAddr("localhost");
  std::string outputFile("synthetic_scheduler_results.csv");

  // Parse input arguments and prepare for the experiment.
  int opt;
  while ((opt = getopt(argc, argv, "hxXco:s:i:t:N:W:C:P:A:T:p:R:D:m:")) != -1) {
    switch (opt) {
      case 'o':
        outputFile = optarg;
        break;
      case 's':
        serverAddr = optarg;
        break;
      case 'i':
        measureIntervalMsec = atoi(optarg);
        break;
      case 't':
        totalExecTimeMsec = atoi(optarg);
        break;
      case 'N':
        numSchedulers = atoi(optarg);
        break;
      case 'W':
        numWorkers = atoi(optarg);
        break;
      case 'C':
        workerCapacity = atoi(optarg);
        break;
      case 'P':
        partitions = atoi(optarg);
        break;
      case 'A':
        scheduleAlgo = optarg;
        break;
      case 'T':
        numTasks = atoi(optarg);
        break;
      case 'p':
        probMultiTx = atof(optarg);
        break;
      case 'R':
        reqPerSec = atof(optarg);
        break;
      case 'D':
        reqDist = optarg;
        break;
      case 'x':
        cleanDB = true;
        break;
      case 'X':
        noSetupDB = true;
        break;
      case 'm':
        maxOutstanding = atoi(optarg);
        break;
      case 'c':
        outputCpuUsage = true;
        break;
      case 'h':
      default:
        Usage(argv);
        break;
    }
  }

  // Check scheduler algorithm type valid here.
  auto algoIt = kAlgorithms.find(scheduleAlgo);
  if (algoIt == kAlgorithms.end()) {
    std::cerr << "Unsupported algorithm: " << scheduleAlgo << std::endl;
    Usage(argv);
  }
  std::cerr << "Scheduler algorithm: " << scheduleAlgo << std::endl;
  std::cerr << "Probability of multi-partition transaction: " << probMultiTx
            << std::endl;
  std::cerr << "Parallel scheduler threads: " << numSchedulers
            << "; workers: " << numWorkers << "; tasks: " << numTasks
            << std::endl;
  std::cerr << "Worker capacity: " << workerCapacity << std::endl;
  std::cerr << "Partitions: " << partitions << std::endl;
  std::cerr << "Output log file: " << outputFile << std::endl;
  std::cerr << "VoltDB server address: " << serverAddr << std::endl;
  std::cerr << "Measurement interval: " << measureIntervalMsec << " msec\n";
  std::cerr << "Total execution time: " << totalExecTimeMsec << " msec\n";
  auto distIt = kDists.find(reqDist);
  if (distIt == kDists.end()) {
    std::cerr << "Unsupported distribution type: " << reqDist << "\n";
    Usage(argv);
  }
  if (reqDist != kNoDist) {
    std::cerr << "Request per sec: " << reqPerSec;
    std::cerr << "; Distribution: " << reqDist << "\n";

    // Calculate per scheduler thread request rate.
    reqPerSecThread = reqPerSec / numSchedulers;
  } else {
    std::cerr << "No distribution type, send as fast as possible.\n";
  }
  std::cerr << "Maximum outstanding requests: " << maxOutstanding << "\n";

  // 1) Initialize database state.
  bool res = false;

  if (!noSetupDB) {
    res = setup(serverAddr);
    if (!res) {
      std::cerr << "Failed to initialize database state." << std::endl;
      exit(1);
    }
  }

  // 2) Run experiments and parse results.
  res = runBenchmark(serverAddr, outputFile);
  if (!res) {
    std::cerr << "Failed to run benchmark." << std::endl;
    exit(1);
  }

  // 3) Clean database state.
  if (cleanDB) {
    res = teardown(serverAddr);
    if (!res) {
      std::cerr << "Failed to tear down database state." << std::endl;
      exit(1);
    }
  }

  return 0;
}

ext: cc

max_stars_repo_name: DBOS-project/dbos-scheduler

max_issues_repo_name: DBOS-project/dbos-scheduler

max_forks_repo_name: DBOS-project/dbos-scheduler


text:
/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#ifndef FirstValidDescriptor_HPP
#define FirstValidDescriptor_HPP

#include "PixelDescriptors/PixelDescriptor.h"

// Boost
#include <boost/property_map/property_map.hpp>

// STL
#include <memory>

/** This class is passed a range of nodes and a query node (the query node is not used, it is just there
  * to conform to the API of other nearest neighbor searchers. It simply returns the first valid source node
  * in the range.
  */
template <typename DescriptorMapType>
struct FirstValidDescriptor
{
  std::shared_ptr<DescriptorMapType> DescriptorMap;

  FirstValidDescriptor(std::shared_ptr<DescriptorMapType> descriptorMap) : DescriptorMap(descriptorMap)
  {
  }

  template <typename TForwardIterator>
  typename TForwardIterator::value_type operator()(TForwardIterator first, TForwardIterator last,
                                                   typename TForwardIterator::value_type query)
  {
    for(TForwardIterator iter = first; iter != last; ++iter)
    {
      if(get(*(this->DescriptorMap), *iter).GetStatus() == PixelDescriptor::SOURCE_NODE)
      {
        return *iter;
      }
    }
    throw std::runtime_error("FirstValidDescriptor: There were no valid descriptors!");
  }
};

#endif

ext: hpp

max_stars_repo_name: jingtangliao/ff

max_issues_repo_name: jingtangliao/ff

max_forks_repo_name: jingtangliao/ff


text:
// Boost.Geometry (aka GGL, Generic Geometry Library)
// This file is manually converted from PROJ4

// Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.

// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Use, modification and distribution is subject to 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)

// This file is converted from PROJ4, http://trac.osgeo.org/proj
// PROJ4 is originally written by Gerald Evenden (then of the USGS)
// PROJ4 is maintained by Frank Warmerdam
// PROJ4 is converted to Geometry Library by
//     Barend Gehrels (Geodan, Amsterdam)
//     Adam Wulkiewicz

// Original copyright notice:

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_ELL_SET_HPP
#define BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_ELL_SET_HPP

#include <string>
#include <vector>

#include <boost/geometry/formulas/eccentricity_sqr.hpp>
#include <boost/geometry/util/math.hpp>

#include <boost/geometry/srs/projections/impl/pj_ellps.hpp>
#include <boost/geometry/srs/projections/impl/pj_param.hpp>
#include <boost/geometry/srs/projections/proj4.hpp>

namespace boost { namespace geometry { namespace projections {

namespace detail {

/* set ellipsoid parameters a and es */
template <typename T>
inline T SIXTH() { return .1666666666666666667; } /* 1/6 */
template <typename T>
inline T RA4() { return .04722222222222222222; } /* 17/360 */
template <typename T>
inline T RA6() { return .02215608465608465608; } /* 67/3024 */
template <typename T>
inline T RV4() { return .06944444444444444444; } /* 5/72 */
template <typename T>
inline T RV6() { return .04243827160493827160; } /* 55/1296 */

/* initialize geographic shape parameters */
template <typename BGParams, typename T>
inline void pj_ell_set(BGParams const& /*bg_params*/, std::vector<pvalue<T> >& parameters, T &a, T &es)
{
    T b = 0.0;
    T e = 0.0;
    std::string name;

    /* check for varying forms of ellipsoid input */
    a = es = 0.;

    /* R takes precedence */
    if (pj_param_f(parameters, "R", a)) {
        /* empty */
    } else { /* probable elliptical figure */

        /* check if ellps present and temporarily append its values to pl */
        name = pj_get_param_s(parameters, "ellps");
        if (! name.empty())
        {
            const int n = sizeof(pj_ellps) / sizeof(pj_ellps[0]);
            int index = -1;
            for (int i = 0; i < n && index == -1; i++)
            {
                if(pj_ellps[i].id == name)
                {
                    index = i;
                }
            }

            if (index == -1) {
                BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
            }

            pj_ellps_type const& pj_ellp = pj_ellps[index];
            parameters.push_back(pj_mkparam<T>("a", pj_ellp.major_v));
            parameters.push_back(pj_mkparam<T>(pj_ellp.ell_n, pj_ellp.ell_v));
        }
        a = pj_get_param_f(parameters, "a");
        if (pj_param_f(parameters, "es", es)) {/* eccentricity squared */
            /* empty */
        } else if (pj_param_f(parameters, "e", e)) { /* eccentricity */
            es = e * e;
        } else if (pj_param_f(parameters, "rf", es)) { /* recip flattening */
            if (!es) {
                BOOST_THROW_EXCEPTION( projection_exception(error_rev_flattening_is_zero) );
            }
            es = 1./ es;
            es = es * (2. - es);
        } else if (pj_param_f(parameters, "f", es)) { /* flattening */
            es = es * (2. - es);
        } else if (pj_param_f(parameters, "b", b)) { /* minor axis */
            es = 1. - (b * b) / (a * a);
        }     /* else es == 0. and sphere of radius a */
        if (!b)
            b = a * sqrt(1. - es);
        /* following options turn ellipsoid into equivalent sphere */
        if (pj_get_param_b(parameters, "R_A")) { /* sphere--area of ellipsoid */
            a *= 1. - es * (SIXTH<T>() + es * (RA4<T>() + es * RA6<T>()));
            es = 0.;
        } else if (pj_get_param_b(parameters, "R_V")) { /* sphere--vol. of ellipsoid */
            a *= 1. - es * (SIXTH<T>() + es * (RV4<T>() + es * RV6<T>()));
            es = 0.;
        } else if (pj_get_param_b(parameters, "R_a")) { /* sphere--arithmetic mean */
            a = .5 * (a + b);
            es = 0.;
        } else if (pj_get_param_b(parameters, "R_g")) { /* sphere--geometric mean */
            a = sqrt(a * b);
            es = 0.;
        } else if (pj_get_param_b(parameters, "R_h")) { /* sphere--harmonic mean */
            a = 2. * a * b / (a + b);
            es = 0.;
        } else {
            T tmp;
            int i = pj_param_r(parameters, "R_lat_a", tmp);
            if (i || /* sphere--arith. */
                pj_param_r(parameters, "R_lat_g", tmp)) { /* or geom. mean at latitude */

                tmp = sin(tmp);
                if (geometry::math::abs(tmp) > geometry::math::half_pi<T>()) {
                    BOOST_THROW_EXCEPTION( projection_exception(error_ref_rad_larger_than_90) );
                }
                tmp = 1. - es * tmp * tmp;
                a *= i ? .5 * (1. - es + tmp) / ( tmp * sqrt(tmp)) :
                    sqrt(1. - es) / tmp;
                es = 0.;
            }
        }
    }

    /* some remaining checks */
    if (es < 0.) {
        BOOST_THROW_EXCEPTION( projection_exception(error_es_less_than_zero) );
    }
    if (a <= 0.) {
        BOOST_THROW_EXCEPTION( projection_exception(error_major_axis_not_given) );
    }
}

template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename T>
inline void pj_ell_set(srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& bg_params,
                       std::vector<pvalue<T> >& /*parameters*/, T &a, T &es)
{
    typedef srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> static_parameters_type;
    typedef typename srs::par4::detail::pick_ellps
        <
            static_parameters_type
        > pick_ellps;

    typename pick_ellps::model_type model = pick_ellps::model(bg_params);

    a = geometry::get_radius<0>(model);
    T b = geometry::get_radius<2>(model);
    es = 0.;
    if (a != b)
    {
        es = formula::eccentricity_sqr<T>(model);

        // Ignore all other parameters passed in string, at least for now
    }

    /* some remaining checks */
    if (es < 0.) {
        BOOST_THROW_EXCEPTION( projection_exception(error_es_less_than_zero) );
    }
    if (a <= 0.) {
        BOOST_THROW_EXCEPTION( projection_exception(error_major_axis_not_given) );
    }
}

template <typename T>
inline void pj_calc_ellipsoid_params(parameters<T> & p, T const& a, T const& es) {
/****************************************************************************************
    Calculate a large number of ancillary ellipsoidal parameters, in addition to
    the two traditional PROJ defining parameters: Semimajor axis, a, and the
    eccentricity squared, es.

    Most of these parameters are fairly cheap to compute in comparison to the overall
    effort involved in initializing a PJ object. They may, however, take a substantial
    part of the time taken in computing an individual point transformation.

    So by providing them up front, we can amortize the (already modest) cost over all
    transformations carried out over the entire lifetime of a PJ object, rather than
    incur that cost for every single transformation.

    Most of the parameter calculations here are based on the "angular eccentricity",
    i.e. the angle, measured from the semiminor axis, of a line going from the north
    pole to one of the foci of the ellipsoid - or in other words: The arc sine of the
    eccentricity.

    The formulae used are mostly taken from:

    Richard H. Rapp: Geometric Geodesy, Part I, (178 pp, 1991).
    Columbus, Ohio:  Dept. of Geodetic Science
    and Surveying, Ohio State University.

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

    p.a = a;
    p.es = es;

    /* Compute some ancillary ellipsoidal parameters */
    if (p.e==0)
        p.e = sqrt(p.es);  /* eccentricity */
    //p.alpha = asin (p.e);  /* angular eccentricity */

    /* second eccentricity */
    //p.e2  = tan (p.alpha);
    //p.e2s = p.e2 * p.e2;

    /* third eccentricity */
    //p.e3    = (0!=p.alpha)? sin (p.alpha) / sqrt(2 - sin (p.alpha)*sin (p.alpha)): 0;
    //p.e3s = p.e3 * p.e3;

    /* flattening */
    //if (0==p.f)
    //    p.f  = 1 - cos (p.alpha);   /* = 1 - sqrt (1 - PIN->es); */
    //p.rf = p.f != 0.0 ? 1.0/p.f: HUGE_VAL;

    /* second flattening */
    //p.f2  = (cos(p.alpha)!=0)? 1/cos (p.alpha) - 1: 0;
    //p.rf2 = p.f2 != 0.0 ? 1/p.f2: HUGE_VAL;

    /* third flattening */
    //p.n  = pow (tan (p.alpha/2), 2);
    //p.rn = p.n != 0.0 ? 1/p.n: HUGE_VAL;

    /* ...and a few more */
    //if (0==p.b)
    //    p.b  = (1 - p.f)*p.a;
    //p.rb = 1. / p.b;
    p.ra = 1. / p.a;

    p.one_es = 1. - p.es;
    if (p.one_es == 0.) {
        BOOST_THROW_EXCEPTION( projection_exception(error_eccentricity_is_one) );
    }

    p.rone_es = 1./p.one_es;
}

} // namespace detail
}}} // namespace boost::geometry::projections

#endif // BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_ELL_SET_HPP

max_stars_repo_name: jonasdmentia/geometry

max_issues_repo_name: jonasdmentia/geometry

max_forks_repo_name: jonasdmentia/geometry


text:
/*
 * 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)
 *
 * Copyright (c) 2009 Helge Bahmann
 * Copyright (c) 2012 Tim Blechmann
 * Copyright (c) 2014 Andrey Semashev
 */
/*!
 * \file   atomic/detail/ops_gcc_x86.hpp
 *
 * This header contains implementation of the \c operations template.
 */

#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_
#define BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_

#include <boost/memory_order.hpp>
#include <boost/atomic/detail/config.hpp>
#include <boost/atomic/detail/storage_type.hpp>
#include <boost/atomic/detail/operations_fwd.hpp>
#include <boost/atomic/capabilities.hpp>
#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)
#include <boost/atomic/detail/ops_gcc_x86_dcas.hpp>
#include <boost/atomic/detail/ops_cas_based.hpp>
#endif

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

#if defined(__x86_64__)
#define BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "rdx"
#else
#define BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "edx"
#endif

namespace boost {
namespace atomics {
namespace detail {

struct gcc_x86_operations_base
{
    static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT
    {
        if ((order & memory_order_release) != 0)
            __asm__ __volatile__ ("" ::: "memory");
    }

    static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT
    {
        if ((order & memory_order_acquire) != 0)
            __asm__ __volatile__ ("" ::: "memory");
    }
};

template< typename T, typename Derived >
struct gcc_x86_operations :
    public gcc_x86_operations_base
{
    typedef T storage_type;

    static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
    {
        if (order != memory_order_seq_cst)
        {
            fence_before(order);
            storage = v;
            fence_after(order);
        }
        else
        {
            Derived::exchange(storage, v, order);
        }
    }

    static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
    {
        storage_type v = storage;
        fence_after(order);
        return v;
    }

    static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
    {
        return Derived::fetch_add(storage, -v, order);
    }

    static BOOST_FORCEINLINE bool compare_exchange_weak(
        storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
    {
        return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order);
    }

    static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
    {
        return !!Derived::exchange(storage, (storage_type)1, order);
    }

    static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
    {
        store(storage, (storage_type)0, order);
    }

    static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
    {
        return true;
    }
};

template< bool Signed >
struct operations< 1u, Signed > :
    public gcc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > >
{
    typedef gcc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > > base_type;
    typedef typename base_type::storage_type storage_type;
    typedef typename make_storage_type< 1u, Signed >::aligned aligned_storage_type;

    static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "lock; xaddb %0, %1"
            : "+q" (v), "+m" (storage)
            :
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "xchgb %0, %1"
            : "+q" (v), "+m" (storage)
            :
            : "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE bool compare_exchange_strong(
        storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
    {
        storage_type previous = expected;
        bool success;
        __asm__ __volatile__
        (
            "lock; cmpxchgb %3, %1\n\t"
            "sete %2"
            : "+a" (previous), "+m" (storage), "=q" (success)
            : "q" (desired)
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        expected = previous;
        return success;
    }

#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\
    __asm__ __volatile__\
    (\
        "xor %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER ", %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "\n\t"\
        ".align 16\n\t"\
        "1: movb %[arg], %%dl\n\t"\
        op " %%al, %%dl\n\t"\
        "lock; cmpxchgb %%dl, %[storage]\n\t"\
        "jne 1b"\
        : [res] "+a" (result), [storage] "+m" (storage)\
        : [arg] "q" (argument)\
        : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER, "memory"\
    )

    static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("andb", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("orb", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("xorb", v, res);
        return res;
    }

#undef BOOST_ATOMIC_DETAIL_CAS_LOOP
};

template< bool Signed >
struct operations< 2u, Signed > :
    public gcc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > >
{
    typedef gcc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > > base_type;
    typedef typename base_type::storage_type storage_type;
    typedef typename make_storage_type< 2u, Signed >::aligned aligned_storage_type;

    static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "lock; xaddw %0, %1"
            : "+q" (v), "+m" (storage)
            :
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "xchgw %0, %1"
            : "+q" (v), "+m" (storage)
            :
            : "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE bool compare_exchange_strong(
        storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
    {
        storage_type previous = expected;
        bool success;
        __asm__ __volatile__
        (
            "lock; cmpxchgw %3, %1\n\t"
            "sete %2"
            : "+a" (previous), "+m" (storage), "=q" (success)
            : "q" (desired)
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        expected = previous;
        return success;
    }

#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\
    __asm__ __volatile__\
    (\
        "xor %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER ", %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "\n\t"\
        ".align 16\n\t"\
        "1: movw %[arg], %%dx\n\t"\
        op " %%ax, %%dx\n\t"\
        "lock; cmpxchgw %%dx, %[storage]\n\t"\
        "jne 1b"\
        : [res] "+a" (result), [storage] "+m" (storage)\
        : [arg] "q" (argument)\
        : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER, "memory"\
    )

    static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("andw", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("orw", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("xorw", v, res);
        return res;
    }

#undef BOOST_ATOMIC_DETAIL_CAS_LOOP
};

template< bool Signed >
struct operations< 4u, Signed > :
    public gcc_x86_operations< typename make_storage_type< 4u, Signed >::type, operations< 4u, Signed > >
{
    typedef gcc_x86_operations< typename make_storage_type< 4u, Signed >::type, operations< 4u, Signed > > base_type;
    typedef typename base_type::storage_type storage_type;
    typedef typename make_storage_type< 4u, Signed >::aligned aligned_storage_type;

    static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "lock; xaddl %0, %1"
            : "+r" (v), "+m" (storage)
            :
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "xchgl %0, %1"
            : "+r" (v), "+m" (storage)
            :
            : "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE bool compare_exchange_strong(
        storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
    {
        storage_type previous = expected;
        bool success;
        __asm__ __volatile__
        (
            "lock; cmpxchgl %3, %1\n\t"
            "sete %2"
            : "+a" (previous), "+m" (storage), "=q" (success)
            : "r" (desired)
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        expected = previous;
        return success;
    }

#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\
    __asm__ __volatile__\
    (\
        "xor %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER ", %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "\n\t"\
        ".align 16\n\t"\
        "1: movl %[arg], %%edx\n\t"\
        op " %%eax, %%edx\n\t"\
        "lock; cmpxchgl %%edx, %[storage]\n\t"\
        "jne 1b"\
        : [res] "+a" (result), [storage] "+m" (storage)\
        : [arg] "r" (argument)\
        : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER, "memory"\
    )

    static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("andl", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("orl", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("xorl", v, res);
        return res;
    }

#undef BOOST_ATOMIC_DETAIL_CAS_LOOP
};

#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B)

template< bool Signed >
struct operations< 8u, Signed > :
    public cas_based_operations< gcc_dcas_x86< Signed > >
{
};

#elif defined(__x86_64__)

template< bool Signed >
struct operations< 8u, Signed > :
    public gcc_x86_operations< typename make_storage_type< 8u, Signed >::type, operations< 8u, Signed > >
{
    typedef gcc_x86_operations< typename make_storage_type< 8u, Signed >::type, operations< 8u, Signed > > base_type;
    typedef typename base_type::storage_type storage_type;
    typedef typename make_storage_type< 8u, Signed >::aligned aligned_storage_type;

    static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "lock; xaddq %0, %1"
            : "+r" (v), "+m" (storage)
            :
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        __asm__ __volatile__
        (
            "xchgq %0, %1"
            : "+r" (v), "+m" (storage)
            :
            : "memory"
        );
        return v;
    }

    static BOOST_FORCEINLINE bool compare_exchange_strong(
        storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
    {
        storage_type previous = expected;
        bool success;
        __asm__ __volatile__
        (
            "lock; cmpxchgq %3, %1\n\t"
            "sete %2"
            : "+a" (previous), "+m" (storage), "=q" (success)
            : "r" (desired)
            : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
        );
        expected = previous;
        return success;
    }

#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\
    __asm__ __volatile__\
    (\
        "xor %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER ", %%" BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER "\n\t"\
        ".align 16\n\t"\
        "1: movq %[arg], %%rdx\n\t"\
        op " %%rax, %%rdx\n\t"\
        "lock; cmpxchgq %%rdx, %[storage]\n\t"\
        "jne 1b"\
        : [res] "+a" (result), [storage] "+m" (storage)\
        : [arg] "r" (argument)\
        : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER, "memory"\
    )

    static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("andq", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("orq", v, res);
        return res;
    }

    static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
    {
        storage_type res = storage;
        BOOST_ATOMIC_DETAIL_CAS_LOOP("xorq", v, res);
        return res;
    }

#undef BOOST_ATOMIC_DETAIL_CAS_LOOP
};

#endif

#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)

template< bool Signed >
struct operations< 16u, Signed > :
    public cas_based_operations< gcc_dcas_x86_64< Signed > >
{
};

#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)

BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT
{
    if (order == memory_order_seq_cst)
    {
        __asm__ __volatile__
        (
#if defined(__x86_64__) || defined(__SSE2__)
            "mfence\n"
#else
            "lock; addl $0, (%%esp)\n"
#endif
            ::: "memory"
        );
    }
    else if ((order & (memory_order_acquire | memory_order_release)) != 0)
    {
        __asm__ __volatile__ ("" ::: "memory");
    }
}

BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT
{
    if (order != memory_order_relaxed)
        __asm__ __volatile__ ("" ::: "memory");
}

} // namespace detail
} // namespace atomics
} // namespace boost

#undef BOOST_ATOMIC_DETAIL_TEMP_CAS_REGISTER

#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_

max_stars_repo_name: kjohannes-intrepidcs/libicsneo

max_issues_repo_name: kjohannes-intrepidcs/libicsneo

max_forks_repo_name: kjohannes-intrepidcs/libicsneo


text: #include <boost/mpl/aux_/config/bind.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#pragma once
#ifdef WIN32
	#include <intrin.h>
#endif
#include <boost/variant.hpp>
#include "spinner/abstbuff.hpp"
#include "spinner/resmgr.hpp"
#include "spinner/dir.hpp"
#include "spinner/size.hpp"
#include "glformat.hpp"
#include "spinner/error.hpp"
#include "spinner/chunk.hpp"
#include "sdlwrap.hpp"
#include <array>
#include "apppath.hpp"
#include "tokenmemory.hpp"
#include "luaimport.hpp"
#include "spinner/structure/wrapper.hpp"

namespace rs {
	//! Tech:Pass の組み合わせを表す
	using GL16Id = std::array<uint8_t, 2>;
	//! ある(Tech:Pass)から別の(Tech:Pass)への遷移を表す
	using GLDiffId = std::array<GL16Id, 2>;
}
namespace std {
	template <> struct hash<::rs::GL16Id> {
		size_t operator() (const ::rs::GL16Id& id) const {
			return (id[1] << 8) | id[0];
		}
	};
	template <> struct hash<::rs::GLDiffId> {
		size_t operator() (const ::rs::GLDiffId& id) const {
			return (hash<::rs::GL16Id>()(id[1]) << 16)
					| (hash<::rs::GL16Id>()(id[0]));
		}
	};
}
namespace rs {
	template <class T>
	class RUser {
		const T&	_t;
		bool		_bRelease;
		public:
			RUser(RUser&& r):
				_t(r._t),
				_bRelease(true)
			{
				r._bRelease = false;
			}
			RUser(const RUser&) = delete;
			RUser(const T& t):
				_t(t),
				_bRelease(true)
			{
				_t.use_begin();
			}
			~RUser() {
				if(_bRelease)
					_t.use_end();
			}
	};

	using OPGLboolean = spn::Optional<GLboolean>;
	using OPGLint = spn::Optional<GLint>;
	using OPGLuint = spn::Optional<GLuint>;
	using OPGLfloat = spn::Optional<GLfloat>;
	#ifndef USE_OPENGLES2
	using OPGLdouble = spn::Optional<GLdouble>;
	#endif

	// ------------------ GL例外クラス ------------------
	using GLGetIV = decltype(&IGL::glGetShaderiv);
	using GLInfoFunc = decltype(&IGL::glGetShaderInfoLog);
	//! GLSLコンパイル関連のエラー基底
	struct GLE_ShProgBase : GLE_Error {
		GLGetIV 	_ivF;
		GLInfoFunc	_infoF;
		GLuint		_id;

		static const char* GetErrorName();
		GLE_ShProgBase(GLGetIV ivF, GLInfoFunc infoF, const std::string& aux, GLuint id);
	};
	//! GLSLシェーダーコンパイルエラー
	struct GLE_ShaderError : GLE_ShProgBase {
		static const char* GetErrorName();
		GLE_ShaderError(const std::string& src, GLuint id);
	};
	//! GLSLプログラムリンクエラー
	struct GLE_ProgramError : GLE_ShProgBase {
		static const char* GetErrorName();
		GLE_ProgramError(GLuint id);
	};
	//! GLSL変数が見つからないエラー
	struct GLE_ParamNotFound : GLE_Error {
		static const char* GetErrorName();
		std::string	_name;
		GLE_ParamNotFound(const std::string& name);
	};
	//! GLSLユーザー変数の型エラー
	struct GLE_InvalidArgument : GLE_Error {
		static const char* GetErrorName();
		std::string	_shName, _argName;
		GLE_InvalidArgument(const std::string& shname, const std::string& argname);
	};
	//! GLXファイルの論理的な記述ミス
	struct GLE_LogicalError : GLE_Error {
		static const char* GetErrorName();
		using GLE_Error::GLE_Error;
	};

	std::shared_ptr<FxBlock> InitFxBlock();
	void ReloadFxBlock(const spn::URI& uri);
	enum MipState {
		NoMipmap,
		MipmapNear,
		MipmapLinear
	};
	enum WrapState {
		ClampToEdge,
		ClampToBorder,
		MirroredRepeat,
		Repeat,
		MirrorClampToEdge,
		_Num
	};
	// ------------------ GLリソース管理 ------------------
	class GLFBufferTmp;
	struct AdaptSDL;
	#define mgr_gl (::rs::GLRes::_ref())
	struct FBInfo {
		GLint		redSize,
					greenSize,
					blueSize,
					alphaSize,
					depthSize,
					stencilSize,
					id;
		bool		bTex;
	};
	using FBInfo_OP = spn::Optional<FBInfo>;
	//! OpenGL関連のリソースマネージャ
	class GLRes : public ResMgrApp<UPResource, GLRes> {
		private:
			using base_type = ResMgrApp<UPResource, GLRes>;
			using Shared_t = GLSharedData<spn::none_t, 0x7fff0000>;
			Shared_t						_sharedObj;

			UPFBuffer						_upFb;
			std::unique_ptr<GLFBufferTmp>	_tmpFb;
			FBInfo_OP						_defaultDepth,
											_defaultColor;
			//! 空のテクスチャ (何もテクスチャをセットしない事を示す)
			/*! デバッグで色を変えたりしてチェックできる */
			std::unique_ptr<HLTex>			_hlEmptyTex;
			//! DeviceLost/Resetの状態管理
			bool	_bInit;
			//! デストラクタ内の時はtrue
			bool	_bInDtor;

			enum ResourceType {
				Texture,
				Effect,
				_Num
			};
			const static std::string cs_rtname[ResourceType::_Num];
			std::function<void (HRes)>	_cbInit;

			//! キューブマップの区別のためのポストフィックス
			spn::Optional<char>	_chPostfix;
			spn::URI _modifyResourceName(spn::URI& key) const override;
			void _initDefaultInfo();
			void _clearDefaultInfo();

		public:
			GLRes();
			~GLRes();
			bool deviceStatus() const;
			bool isInDtor() const;
			void onDeviceLost();
			void onDeviceReset();

			//! ベースクラスのacquireメソッドを隠す為のダミー
			void acquire();

			const std::string& getResourceName(spn::SHandle sh) const override;
			static void LuaExport(LuaState& lsc);
			// ------------ Texture ------------
			//! ファイルからテクスチャを読み込む
			/*! 圧縮テクスチャはファイルヘッダで判定
				\param[in] fmt OpenGLの内部フォーマット(not ファイルのフォーマット)<br>
								指定しなければファイルから推定 */
			HLTex loadTextureUri(const spn::URI& uri, MipState miplevel=NoMipmap, OPInCompressedFmt fmt=spn::none);
			HLTex loadTexture(const std::string& name, MipState miplevel=NoMipmap, OPInCompressedFmt fmt=spn::none);
			//! 連番ファイルからキューブテクスチャを作成
			HLTex loadCubeTextureUri(const spn::URI& uri, MipState miplevel=NoMipmap, OPInCompressedFmt fmt=spn::none);
			HLTex loadCubeTexture(const std::string& name, MipState miplevel=NoMipmap, OPInCompressedFmt fmt=spn::none);
			//! 個別のファイルからキューブテクスチャを作成
			/*! 画像サイズとフォーマットは全て一致していなければならない */
			HLTex _loadCubeTexture(MipState miplevel, OPInCompressedFmt fmt, const spn::URI& uri0, const spn::URI& uri1, const spn::URI& uri2,
								  const spn::URI& uri3, const spn::URI& uri4, const spn::URI& uri5);
			template <class... Ts>
			HLTex loadCubeTextureFromResource(MipState miplevel, OPInCompressedFmt fmt, Ts&&... ts) {
				return loadCubeTexture(miplevel, fmt, _uriFromResourceName(std::forward<Ts>(ts))...);
			}
			HLTex _createTexture(bool bCube, const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore);
			//! 空のテクスチャを作成
			/*! 領域だけ確保 */
			HLTex createTexture(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore);
			/*! 用意したデータで初期化 */
			HLTex createTextureInit(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore, GLTypeFmt srcFmt, spn::AB_Byte data);
			//! 空のキューブテクスチャを作成
			HLTex createCubeTexture(const spn::Size& size, GLInSizedFmt fmt, bool bRestore, bool bStream);
			//! 共通のデータで初期化
			HLTex createCubeTextureInit(const spn::Size& size, GLInSizedFmt fmt, bool bRestore, bool bStream, spn::AB_Byte data);
			//! 個別のデータで初期化
			HLTex createCubeTextureInit(const spn::Size& size, GLInSizedFmt fmt, bool bRestore, bool bStream,
									spn::AB_Byte data0, spn::AB_Byte data1, spn::AB_Byte data2,
									spn::AB_Byte data3, spn::AB_Byte data4, spn::AB_Byte data5);

			// ------------ Shader ------------
			//! 文字列からシェーダーを作成
			HLSh makeShader(ShType type, const std::string& src);

			//! 複数のシェーダーからプログラムを作成 (vertex, geometry, fragment)
			HLProg makeProgram(HSh vsh, HSh gsh, HSh fsh);
			//! 複数のシェーダーからプログラムを作成 (vertex, fragment)
			HLProg makeProgram(HSh vsh, HSh fsh);

			// ------------ Buffer ------------
			using CBCreateFx = std::function<IEffect* (const std::string&)>;
			//! ファイルからエフェクトの読み込み
			HLFx loadEffect(const std::string& name, const CBCreateFx& cb);
			//! エフェクトファイルの置き換え
			UPResource replaceEffect(HLFx& fx, const CBCreateFx& cb);
			//! 頂点バッファの確保
			HLVb makeVBuffer(GLuint dtype);
			//! インデックスバッファの確保
			HLIb makeIBuffer(GLuint dtype);

			HTex getEmptyTexture() const;
			LHdl _common(const std::string& key, std::function<UPResource(const spn::URI&)> cb);
			GLFBufferTmp& getTmpFramebuffer() const;
			// --- from ResMgrBase ---
			spn::LHandle loadResource(spn::AdaptStream& ast, const spn::URI& uri) override;

			// ------------ FrameBuffer ------------
			HLFb makeFBuffer();
			// ------------ RenderBuffer ------------
			HLRb makeRBuffer(int w, int h, GLInRenderFmt fmt);

			const FBInfo_OP& getDefaultDepth() const;
			const FBInfo_OP& getDefaultColor() const;

			decltype(std::declval<Shared_t>().lock()) lockGL();
	};

	using Priority = uint32_t;
	using Priority64 = uint64_t;
	namespace draw {
		template <class T>
		struct TokenR : TokenT<T> {
			HLRes	_hlRes;
			TokenR(HRes hRes): _hlRes(hRes) {}
		};
		template <class T>
		struct Uniform : TokenR<T> {
			GLint	idUnif;
			Uniform(HRes hRes, GLint id): TokenR<T>(hRes), idUnif(id) {}
		};
		struct ClearParam {
			spn::Optional<spn::Vec4>	color;
			spn::Optional<float>		depth;
			spn::Optional<uint32_t>		stencil;
		};
		class Clear : public TokenT<Clear> {
			private:
				ClearParam	_param;
			public:
				Clear(const ClearParam& p);
				void exec() override;
		};
		class Viewport : public TokenT<Viewport> {
			private:
				bool		_bPixel;
				spn::RectF	_rect;
			public:
				Viewport(bool bPixel, const spn::RectF& r);
				void exec() override;
		};

		void Unif_Vec_Exec(int idx, GLint id, const void* ptr, int n);
		void Unif_Mat_Exec(int idx, GLint id, const void* ptr, int n, bool bT);
		//! ivec[1-4], fvec[1-4]対応
		template <class T, int DN>
		class Unif_Vec : public Uniform<Unif_Vec<T,DN>> {
			protected:
				using base_t = Uniform<Unif_Vec<T,DN>>;
				using SPT = std::shared_ptr<T>;
				SPT		_data;
				int		_nAr;

			public:
				template <bool A>
				Unif_Vec(GLint id, const spn::VecT<DN,A>& v): Unif_Vec(id, v.m, DN, 1) {}
				template <bool A>
				Unif_Vec(GLint id, const spn::VecT<DN,A>* vp, int n): Unif_Vec(id, vp->m, DN, n) {}
				Unif_Vec(GLint id, const T* v, int nElem, int n):
					base_t(HRes(), id),
					_data(new T[nElem*n]),
					_nAr(n)
				{
					std::memcpy(_data.get(), v, sizeof(T)*nElem*n);
				}
				void exec() override {
					Unif_Vec_Exec(std::is_integral<T>::value * 4 + DN-1, base_t::idUnif, _data.get(), _nAr);
				}
		};
		template <class T, int DN>
		class Unif_Mat : public Unif_Vec<T,DN> {
			private:
				using base_t = Unif_Vec<T,DN>;
				bool	_bT;
			public:
				template <bool A>
				Unif_Mat(GLint id, const spn::MatT<DN,DN,A>& m, bool bT): Unif_Mat(id, &m, 1, bT) {}
				template <bool A>
				Unif_Mat(GLint id, const spn::MatT<DN,DN,A>* mp, int n, bool bT):
					base_t(id, mp->data, DN*DN, n), _bT(bT) {}
				void exec() override {
					Unif_Mat_Exec(DN-2, base_t::idUnif, base_t::_data.get(), base_t::_nAr, _bT);
				}
				void clone(TokenDst& dst) const override {
					new(dst.allocate_memory(getSize(), draw::CalcTokenOffset<Unif_Mat>())) Unif_Mat(*this);
				}
				void takeout(TokenDst& dst) override {
					new(dst.allocate_memory(getSize(), draw::CalcTokenOffset<Unif_Mat>())) Unif_Mat(std::move(*this));
				}
				std::size_t getSize() const override {
					return sizeof(*this);
				}
		};
	}
	//! OpenGL関連のリソース
	/*! Android用にデバイスロスト対応 */
	struct IGLResource : spn::EnableFromThis<HRes> {
		virtual void onDeviceLost() {}
		virtual void onDeviceReset() {}
		virtual ~IGLResource() {}
		virtual const std::string& getResourceName() const;
	};

	//! GLシェーダークラス
	class GLShader : public IGLResource {
		GLuint				_idSh;
		ShType				_flag;
		const std::string	_source;
		void _initShader();

		public:
			//! 空シェーダーの初期化
			GLShader();
			GLShader(ShType flag, const std::string& src);
			~GLShader() override;
			bool isEmpty() const;
			int getShaderID() const;
			ShType getShaderType() const;
			void onDeviceLost() override;
			void onDeviceReset() override;
	};

	namespace draw {
		class Buffer;
		class VStream;
	}
	class GLBufferCore {
		private:
			friend class RUser<GLBufferCore>;
			friend class draw::Buffer;
			friend class draw::VStream;
			void use_begin() const;
			void use_end() const;
		protected:
			GLuint		_buffType,			//!< VERTEX_BUFFERなど
						_drawType,			//!< STATIC_DRAWなどのフラグ
						_stride,			//!< 要素1つのバイトサイズ
						_idBuff;			//!< OpenGLバッファID
		public:
			GLBufferCore(GLuint flag, GLuint dtype);
			virtual ~GLBufferCore() {}

			RUser<GLBufferCore> use() const;

			GLuint getBuffID() const;
			GLuint getBuffType() const;
			GLuint getStride() const;
	};
	namespace draw {
		class Buffer : public GLBufferCore, public TokenR<Buffer> {
			public:
				Buffer(const GLBufferCore& core, HRes hRes);
				void exec() override;
		};
		class Program : public TokenR<Program> {
			GLuint		_idProg;
			public:
				Program(HRes hRes, GLuint idProg);
				void exec() override;
		};
	}

	/*	getDrawTokenの役割:
		描画時にしか必要ないAPI呼び出しを纏める
		ただしDrawThreadからはリソースハンドルの参照が出来ないのでOpenGLの番号をそのまま格納 */
	template <class T>
	struct is_vector { constexpr static int value = 0; };
	template <class T>
	struct is_vector<std::vector<T>> { constexpr static int value = 1; };
	//! OpenGLバッファクラス
	class GLBuffer : public IGLResource, public GLBufferCore {
		using SPBuff = std::shared_ptr<void>;
		SPBuff			_buff;			//!< 再構築の際に必要となるデータ実体(std::vector<T>)
		void*			_pBuffer;		//!< bufferの先頭ポインタ
		GLuint			_buffSize;		//!< bufferのバイトサイズ
		void	_initData();

		template <class T>
		using Raw = typename std::decay<T>::type;
		template <class T>
		using ChkIfVector = typename std::enable_if<is_vector<Raw<T>>::value>::type;
		template <class T, class = ChkIfVector<T>>
		void _setVec(T&& src, GLuint stride) {
			using RawType = Raw<T>;
			auto fnDeleter = [](void* ptr) {
				auto* rt = reinterpret_cast<RawType*>(ptr);
				delete rt;
			};
			_stride = stride;
			_buffSize = src.size() * sizeof(typename Raw<T>::value_type);
			RawType* rt = new RawType(std::forward<T>(src));
			_pBuffer = rt->data();
			_buff = SPBuff(static_cast<void*>(rt), fnDeleter);
		}

		public:
			GLBuffer(GLuint flag, GLuint dtype);
			GLBuffer(const GLBuffer&) = delete;
			~GLBuffer() override;

			// 全域を書き換え
			void initData(const void* src, size_t nElem, GLuint stride);
			template <class T, class = ChkIfVector<T>>
			void initData(T&& src, GLuint stride=sizeof(typename Raw<T>::value_type)) {
				_setVec(std::forward<T>(src), stride);
				_initData();
			}
			// 部分的に書き換え
			void updateData(const void* src, size_t nElem, GLuint offset);
			GLuint getSize() const;
			GLuint getNElem() const;

			void onDeviceLost() override;
			void onDeviceReset() override;
			draw::Buffer getDrawToken() const;
	};
	// バッファのDrawTokenはVDeclとの兼ね合いからそのままリストに積まずに
	// StreamTagで一旦処理するのでスマートポインタではなく直接出力する

	//! 頂点バッファ
	class GLVBuffer : public GLBuffer {
		public:
			GLVBuffer(GLuint dtype);
	};
	//! インデックスバッファ
	class GLIBuffer : public GLBuffer {
		public:
			GLIBuffer(GLuint dtype);
			using GLBuffer::initData;
			void initData(const GLubyte* src, size_t nElem);
			void initData(const GLushort* src, size_t nElem);

			void updateData(const GLushort* src, size_t nElem, GLuint offset);
			void updateData(const GLubyte* src, size_t nElem, GLuint offset);
			GLenum getSizeFlag() const;
			static GLenum GetSizeFlag(int stride);
	};

	struct GLParamInfo : GLSLFormatDesc {
		std::string name;
		GLParamInfo() = default;
		GLParamInfo(const GLParamInfo&) = default;
		GLParamInfo(const GLSLFormatDesc& desc);
	};
	//! GLSLプログラムクラス
	class GLProgram : public IGLResource {
		HLSh		_shader[ShType::NUM_SHTYPE];
		GLuint		_idProg;

		void _initProgram();
		using InfoF = void (IGL::*)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*);
		GLParamInfo _getActiveParam(int n, InfoF infoF) const;
		int _getNumParam(GLenum flag) const;
		void _setShader(HSh hSh);

		void _init() {
			_initProgram();
		}
		template <class T, class... Ts>
		void _init(const T& t, const Ts&... ts) {
			_setShader(t);
			_init(ts...);
		}

		public:
			template <class... Ts>
			GLProgram(const Ts&... ts) {
				_init(ts...);
			}
			~GLProgram() override;
			void onDeviceLost() override;
			void onDeviceReset() override;
			void getDrawToken(draw::TokenDst& dst) const;
			const HLSh& getShader(ShType type) const;
			OPGLint getUniformID(const std::string& name) const;
			OPGLint getAttribID(const std::string& name) const;
			GLuint getProgramID() const;
			int getNActiveAttribute() const;
			int getNActiveUniform() const;
			GLParamInfo getActiveAttribute(int n) const;
			GLParamInfo getActiveUniform(int n) const;
			void use() const;
	};
	enum class CubeFace {
		PositiveX,
		NegativeX,
		PositiveY,
		NegativeY,
		PositiveZ,
		NegativeZ,
		Num
	};

	namespace draw {
		class Texture;
		class TextureA;
	}
	//! OpenGLテクスチャインタフェース
	/*!	フィルターはNEARESTとLINEARしか無いからboolで管理 */
	class IGLTexture : public IGLResource {
		public:
			friend class RUser<IGLTexture>;
			friend class draw::Texture;
			friend class draw::TextureA;

			void use_begin() const;
			void use_end() const;
		protected:
			GLuint		_idTex;
			int			_iLinearMag,	//!< Linearの場合は1, Nearestは0
						_iLinearMin;
			WrapState	_wrapS,
						_wrapT;
			GLuint		_actID;		//!< セットしようとしているActiveTextureID (for Use())
			//! [mipLevel][Nearest / Linear]
			const static GLuint cs_Filter[3][2];
			const MipState		_mipLevel;
			GLuint				_texFlag,	//!< TEXTURE_2D or TEXTURE_CUBE_MAP
								_faceFlag;	//!< TEXTURE_2D or TEXTURE_CUBE_MAP_POSITIVE_X
			float				_coeff;
			spn::Size			_size;
			OPInCompressedFmt	_format;	//!< 値が無効 = 不定

			bool _onDeviceReset();
			IGLTexture(MipState miplevel, OPInCompressedFmt fmt, const spn::Size& sz, bool bCube);
			IGLTexture(const IGLTexture& t);

		public:
			IGLTexture(IGLTexture&& t);
			virtual ~IGLTexture();

			void setFilter(bool bLinearMag, bool bLinearMin);
			void setLinear(bool bLinear);
			void setAnisotropicCoeff(float coeff);
			void setUVWrap(WrapState s, WrapState t);
			void setWrap(WrapState st);
			const std::string& getResourceName() const override;

			RUser<IGLTexture> use() const;

			const spn::Size& getSize() const;
			GLint getTextureID() const;
			const OPInCompressedFmt& getFormat() const;
			GLenum getTexFlag() const;
			GLenum getFaceFlag(CubeFace face=CubeFace::PositiveX) const;
			void onDeviceLost() override;
			//! テクスチャユニット番号を指定してBind
			void setActiveID(GLuint n);

			static bool IsMipmap(MipState level);
			bool isMipmap() const;
			//! 内容をファイルに保存 (主にデバッグ用)
			void save(const std::string& path, CubeFace face=CubeFace::PositiveX);

			bool isCubemap() const;
			bool operator == (const IGLTexture& t) const;
			spn::ByteBuff readData(GLInFmt internalFmt, GLTypeFmt elem, int level=0, CubeFace face=CubeFace::PositiveX) const;
			spn::ByteBuff readRect(GLInFmt internalFmt, GLTypeFmt elem, const spn::Rect& rect, CubeFace face=CubeFace::PositiveX) const;
			/*! \param[in] uniform変数の番号
				\param[in] index idで示されるuniform変数配列のインデックス(デフォルト=0)
				\param[in] hRes 自身のリソースハンドル */
			void getDrawToken(draw::TokenDst& dst, GLint id, int index, int actID);
	};
	namespace draw {
		// 連番テクスチャはUniformID + Indexとして設定
		class Texture : public IGLTexture, public Uniform<Texture> {
			public:
				Texture(HRes hRes, GLint id, int index, int baseActID, const IGLTexture& t);
				virtual ~Texture();
				void exec() override;
		};
		class TextureA : public Uniform<TextureA> {
			private:
				using TexA = std::vector<Texture>;
				TexA	_texA;
			public:
				TextureA(GLint id, const HRes* hRes, const IGLTexture** tp, int baseActID, int nTex);
				void exec() override;
		};
	}

	template <class T>
	struct IOPArray {
		virtual int getNPacked() const = 0;
		virtual const T& getPacked(int n) const = 0;
		virtual ~IOPArray() {}
		virtual uint32_t getID() const = 0;
		virtual bool operator == (const IOPArray& p) const = 0;
	};
	template <class T, int N>
	class OPArray : public IOPArray<T> {
		spn::Optional<T>	_packed[N];

		void _init(spn::Optional<T>* /*dst*/) {}
		template <class TA, class... Ts>
		void _init(spn::Optional<T>* dst, TA&& ta, Ts&&... ts) {
			*dst++ = std::forward<TA>(ta);
			_init(dst, std::forward<Ts>(ts)...);
		}
		public:
			template <class... Ts>
			OPArray(Ts&&... ts) {
				static_assert(sizeof...(Ts)==N, "invalid number of argument(s)");
				_init(_packed, std::forward<Ts>(ts)...);
			}
			int getNPacked() const override { return N; }
			const T& getPacked(int n) const override {
				Assert(Trap, n<=N)
				return *_packed[n];
			}
			bool operator == (const IOPArray<T>& p) const override {
				if(getID()==p.getID() && getNPacked()==p.getNPacked()) {
					auto& p2 = reinterpret_cast<const OPArray&>(p);
					for(int i=0 ; i<N ; i++) {
						if(_packed[i] != p2._packed[i])
							return false;
					}
					return true;
				}
				return false;
			}
			uint32_t getID() const override { return spn::MakeChunk('P','a','c','k'); }
	};
	using SPPackURI = std::shared_ptr<IOPArray<spn::URI>>;
	//! ユーザー定義の空テクスチャ
	/*! DeviceLost時の復元は任意
		内部バッファはDeviceLost用であり、DeviceがActiveな時はnone
		フォーマット変換は全てOpenGLにさせる
		書き込み不可の時は最初の一度だけ書き込める */
	class Texture_Mem : public IGLTexture {
		using OPBuff = spn::Optional<spn::ByteBuff>;
		using OPFormat = spn::Optional<GLTypeFmt>;
		OPBuff		_buff;			//!< DeviceLost時用のバッファ
		OPFormat	_typeFormat;	//!< _buffに格納されているデータの形式(Type)

		//bool		_bStream;		//!< 頻繁に書き換えられるか(の、ヒント)
		bool		_bRestore;
		//! テクスチャフォーマットから必要なサイズを計算してバッファを用意する
		const GLFormatDesc& _prepareBuffer();
		public:
			Texture_Mem(bool bCube, GLInSizedFmt fmt, const spn::Size& sz, bool bStream, bool bRestore);
			void onDeviceReset() override;
			void onDeviceLost() override;
			//! テクスチャ全部書き換え = バッファも置き換え
			/*! \param[in] fmt テクスチャのフォーマット
				\param[in] srcFmt 入力フォーマット(Type)
				\param[in] bRestore trueなら内部バッファにコピーを持っておいてDeviceLostに備える
				\param[in] face Cubemapにおける面 */
			void writeData(spn::AB_Byte buff, GLTypeFmt srcFmt, CubeFace face=CubeFace::PositiveX);
			//! 部分的に書き込み
			/*! \param[in] ofsX 書き込み先オフセット X
				\param[in] ofsY 書き込み先オフセット Y
				\param[in] srcFmt 入力フォーマット(Type)
				\param[in] face Cubemapにおける面 */
			void writeRect(spn::AB_Byte buff, const spn::Rect& rect, GLTypeFmt srcFmt, CubeFace face=CubeFace::PositiveX);
	};
	//! 画像ファイルから2Dテクスチャを読む
	/*! DeviceReset時:
		再度ファイルから読み出す */
	class Texture_StaticURI : public IGLTexture {
		spn::URI			_uri;
		OPInCompressedFmt	_opFmt;
		public:
			static std::pair<spn::Size, GLInCompressedFmt> LoadTexture(IGLTexture& tex, HRW hRW, CubeFace face);
			Texture_StaticURI(Texture_StaticURI&& t);
			Texture_StaticURI(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt);
			void onDeviceReset() override;
	};
	//! 連番または6つの画像ファイルからCubeテクスチャを読む
	class Texture_StaticCubeURI : public IGLTexture {
		SPPackURI			_uri;
		OPInCompressedFmt	_opFmt;
		public:
			Texture_StaticCubeURI(Texture_StaticCubeURI&& t);
			Texture_StaticCubeURI(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt);
			Texture_StaticCubeURI(const spn::URI& uri0, const spn::URI& uri1, const spn::URI& uri2,
				const spn::URI& uri3, const spn::URI& uri4, const spn::URI& uri5, MipState miplevel, OPInCompressedFmt fmt);
			void onDeviceReset() override;
	};

	//! デバッグ用テクスチャ模様生成インタフェース
	struct ITDGen {
		virtual ~ITDGen() {}
		virtual uint32_t getFormat() const = 0;
		virtual bool isSingle() const = 0;
		virtual spn::ByteBuff generate(const spn::Size& size, CubeFace face=CubeFace::PositiveX) const = 0;
	};
	using UPTDGen = std::unique_ptr<ITDGen>;
	#define DEF_DEBUGGEN \
		uint32_t getFormat() const override; \
		bool isSingle() const override; \
		spn::ByteBuff generate(const spn::Size& size, CubeFace face) const override;

	//! 2色チェッカー
	class TDChecker : public ITDGen {
		spn::Vec4	_col[2];
		int			_nDivW, _nDivH;
		public:
			TDChecker(const spn::Vec4& col0, const spn::Vec4& col1, int nDivW, int nDivH);
			DEF_DEBUGGEN
	};
	//! カラーチェッカー
	/*! 準モンテカルロで色を決定 */
	class TDCChecker : public ITDGen {
		// int			_nDivW, _nDivH;
		public:
			TDCChecker(int nDivW, int nDivH);
			DEF_DEBUGGEN
	};
	//! ベタ地と1テクセル枠
	class TDBorder : public ITDGen {
		public:
			TDBorder(const spn::Vec4& col, const spn::Vec4& bcol);
			DEF_DEBUGGEN
	};

	//! デバッグ用のテクスチャ
	/*! DeviceLost時:
		再度生成し直す */
	class Texture_Debug : public IGLTexture {
		// デバッグ用なので他との共有を考えず、UniquePtrとする
		UPTDGen		_gen;
		public:
			Texture_Debug(ITDGen* gen, const spn::Size& size, bool bCube, MipState miplevel);
			void onDeviceReset() override;
	};

	//! OpenGL: RenderBufferObjectインタフェース
	/*! Use/EndインタフェースはユーザーがRenderbufferに直接何かする事は無いが内部的に使用 */
	class GLRBuffer : public IGLResource {
		public:
			//! DeviceLost時の挙動
			enum OnLost {
				NONE,		//!< 何もしない(領域はゴミデータになる)
				CLEAR,		//!< 単色でクリア
				RESTORE,	//!< 事前に保存しておいた内容で復元
				NUM_ONLOST
			};
			friend class RUser<GLRBuffer>;
			void use_begin() const;
			void use_end() const;
			// OpenGL ES2.0だとglDrawPixelsが使えない
		private:
			using F_LOST = std::function<void (GLFBufferTmp&,GLRBuffer&)>;
			const static F_LOST cs_onLost[NUM_ONLOST],
								cs_onReset[NUM_ONLOST];
			GLuint		_idRbo;
			OnLost		_behLost;

			using Res = boost::variant<boost::blank, spn::Vec4, spn::ByteBuff>;
			Res				_restoreInfo;
			GLTypeFmt		_buffFmt;
			GLFormatV		_fmt;
			spn::Size		_size;
			//! 現在指定されているサイズとフォーマットでRenderbuffer領域を確保 (内部用)
			void allocate();

		public:
			GLRBuffer(int w, int h, GLInRenderFmt fmt);
			~GLRBuffer();
			void onDeviceReset() override;
			void onDeviceLost() override;

			RUser<GLRBuffer> use() const;

			void setOnLost(OnLost beh, const spn::Vec4* color=nullptr);
			GLuint getBufferID() const;
			const spn::Size& getSize() const;
			const GLFormatV& getFormat() const;
			const std::string& getResourceName() const override;
	};

	class GLFBufferCore {
		public:
			friend class RUser<GLFBufferCore>;
			void use_begin() const;
			void use_end() const;
			static thread_local spn::Size s_fbSize;

			struct Att {
				enum Id {
					COLOR0,
					#ifndef USE_OPENGLES2
						COLOR1,
						COLOR2,
						COLOR3,
					#endif
					DEPTH,
					STENCIL,
					NUM_ATTACHMENT,
					DEPTH_STENCIL = 0xffff
				};
			};
			static FBInfo GetCurrentInfo(Att::Id att);
			static GLenum _AttIDtoGL(Att::Id att);
			void _attachRenderbuffer(Att::Id aId, GLuint rb);
			void _attachCubeTexture(Att::Id aId, GLuint faceFlag, GLuint tb);
			void _attachTexture(Att::Id aId, GLuint tb);
			using TexRes = std::pair<HLTex, CubeFace>;
			struct RawTex : spn::Wrapper<GLuint> {
				using Wrapper::Wrapper;
			};
			struct RawRb : spn::Wrapper<GLuint> {
				using Wrapper::Wrapper;
			};
			// attachは受け付けるがハンドルを格納するだけであり、実際OpenGLにセットされるのはDTh
		protected:
			// 内部がTextureかRenderBufferなので、それらを格納できる型を定義
			using Res = boost::variant<boost::blank, RawTex, RawRb, TexRes, HLRb>;
			GLuint	_idFbo;
			static void _SetCurrentFBSize(const spn::Size& s);

		public:
			static const spn::Size& GetCurrentFBSize();
			GLFBufferCore(GLuint id);
			GLuint getBufferID() const;

			RUser<GLFBufferCore> use() const;
	};

	namespace draw {
		// 毎回GLでAttachする
		class FrameBuff : public GLFBufferCore, public TokenR<FrameBuff> {
			struct Visitor;
			struct Pair {
				bool	bTex;
				Res		handle;
				GLuint	idRes,		// 0番は無効
						faceFlag;
			} _ent[Att::NUM_ATTACHMENT];
			const spn::Size	_size;	//!< Colo0バッファのサイズ

			public:
				// from GLFBufferTmp
				FrameBuff(GLuint idFb, const spn::Size& s);
				// from GLFBuffer
				FrameBuff(HRes hRes, GLuint idFb, const Res (&att)[Att::NUM_ATTACHMENT]);

				void exec() override;
		};
	}
	//! 非ハンドル管理で一時的にFramebufferを使いたい時のヘルパークラス (内部用)
	class GLFBufferTmp : public GLFBufferCore {
		private:
			static void _Attach(GLenum flag, GLuint rb);
			const spn::Size	_size;
		public:
			GLFBufferTmp(GLuint idFb, const spn::Size& s);
			void attachRBuffer(Att::Id att, GLuint rb);
			void attachTexture(Att::Id att, GLuint id);
			void attachCubeTexture(Att::Id att, GLuint id, GLuint face);
			void use_end() const;

			void getDrawToken(draw::TokenDst& dst) const;
			RUser<GLFBufferTmp> use() const;
	};
	using Size_OP = spn::Optional<spn::Size>;
	//! OpenGL: FrameBufferObjectインタフェース
	class GLFBuffer : public GLFBufferCore, public IGLResource {
		// GLuintは内部処理用 = RenderbufferのID
		Res	_attachment[Att::NUM_ATTACHMENT];
		template <class T>
		void _attachIt(Att::Id att, const T& arg);

		public:
			static Size_OP GetAttachmentSize(const Res (&att)[Att::NUM_ATTACHMENT], Att::Id id);
			static void LuaExport(LuaState& lsc);
			GLFBuffer();
			~GLFBuffer();
			void attachRBuffer(Att::Id att, HRb hRb);
			void attachTexture(Att::Id att, HTex hTex);
			void attachTextureFace(Att::Id att, HTex hTex, CubeFace face);
			void attachRawRBuffer(Att::Id att, GLuint idRb);
			void attachRawTexture(Att::Id att, GLuint idTex);
			void attachOther(Att::Id attDst, Att::Id attSrc, HFb hFb);
			void detach(Att::Id att);

			void onDeviceReset() override;
			void onDeviceLost() override;
			void getDrawToken(draw::TokenDst& dst) const;
			const Res& getAttachment(Att::Id att) const;
			HTex getAttachmentAsTexture(Att::Id id) const;
			HRb getAttachmentAsRBuffer(Att::Id id) const;
			Size_OP getAttachmentSize(Att::Id att) const;
			const std::string& getResourceName() const override;
	};
}
DEF_LUAIMPORT(rs::GLRes)
DEF_LUAIMPORT(rs::GLRBuffer)
DEF_LUAIMPORT(rs::GLFBuffer)
DEF_LUAIMPORT(rs::IGLTexture)

max_stars_repo_name: degarashi/resonant

max_issues_repo_name: degarashi/resonant

max_forks_repo_name: degarashi/resonant


text:
#define BOOST_TEST_MAIN TestCompressedSparse
#include <boost/test/unit_test.hpp>
#include <stdexcept>
#include <string>
#include <vector>
#include <zmq.hpp>
#include <thread>
#include <atomic>
#include <sam/Edge.hpp>
#include <sam/VastNetflow.hpp>
#include <sam/VastNetflowGenerators.hpp>
#include <sam/CompressedSparse.hpp>
#include <sam/Util.hpp>

using namespace sam;

typedef CompressedSparse<VastNetflow,
   DestIp, SourceIp, TimeSeconds, DurationSeconds,
   StringHashFunction, StringEqualityFunction> GraphType;

BOOST_AUTO_TEST_CASE( test_compressed_sparse_one_vertex )
{
  /**
   * Tests when we have only one source vertex.
   */
  size_t capacity = 1000;
  double window = 1000; //Make big window so we don't lose anything
  auto graph = new GraphType(capacity, window);

  int numThreads = 100;
  int numExamples = 1000;
  auto id = new std::atomic<int>(0);

  std::vector<std::thread> threads;
  for (int i = 0; i < numThreads; i++) {
    threads.push_back(std::thread([graph, id, i, numExamples]() {

      UniformDestPort generator("192.168.0.1", 1);
      //UniformDestPort generator("192.168.0." +
      //  boost::lexical_cast<std::string>(i), 1);

      for (int j =0; j < numExamples; j++) {
        VastNetflow netflow = makeNetflow(id->fetch_add(1),
                                          generator.generate());
        graph->addEdge(netflow);
      }
    }));

  }

  for (int i = 0; i < numThreads; i++) {
    threads[i].join();
  }

  size_t count = graph->countEdges();
  BOOST_CHECK_EQUAL(count, numThreads * numExamples);
}

BOOST_AUTO_TEST_CASE( test_compressed_sparse_many_vertices )
{
  /**
   * Tests when we have lots of source vertices (sourc ips)
   */
  size_t capacity = 1000;
  double window = 1000; //Make big window so we don't lose anything
  auto graph = new GraphType(capacity, window);

  int numThreads = 100;
  int numExamples = 1000;
  auto id = new std::atomic<int>(0);

  std::vector<std::thread> threads;
  for (int i = 0; i < numThreads; i++) {
    threads.push_back(std::thread([graph, id, i, numExamples]() {

      UniformDestPort generator("192.168.0.1", 1);
      //UniformDestPort generator("192.168.0." +
      //  boost::lexical_cast<std::string>(i), 1);

      for (int j =0; j < numExamples; j++) {
        VastNetflow netflow = makeNetflow(id->fetch_add(1),
                                          generator.generate());
        graph->addEdge(netflow);
      }

    }));

  }

  for (int i = 0; i < numThreads; i++) {
    threads[i].join();
  }

  size_t count = graph->countEdges();
  BOOST_CHECK_EQUAL(count, numThreads * numExamples);
}

BOOST_AUTO_TEST_CASE( test_compressed_sparse_small_capacity )
{
  /**
   * This tests adding a bunch of edges when the capacity is just 1, so
   * we make sure that even if the capacity is smaller than the number of
   * source vertices, it can still handle it.
   */
  size_t capacity = 1;
  double window = 1000; //Make big window so we don't lose anything
  auto graph = new GraphType(capacity, window);

  int numThreads = 100;
  int numExamples = 1;
  auto id = new std::atomic<int>(0);

  std::vector<std::thread> threads;
  for (int i = 0; i < numThreads; i++) {
    threads.push_back(std::thread([graph, id, i, numExamples]() {

      //UniformDestPort generator("192.168.0.1", 1);
      UniformDestPort generator("192.168.0." +
        boost::lexical_cast<std::string>(i), 1);

      for (int j =0; j < numExamples; j++) {
        VastNetflow netflow = makeNetflow(id->fetch_add(1),
                                          generator.generate());
        graph->addEdge(netflow);
      }

    }));

  }

  for (int i = 0; i < numThreads; i++) {
    threads[i].join();
  }

  size_t count = graph->countEdges();
  BOOST_CHECK_EQUAL(count, numThreads * numExamples);
}

BOOST_AUTO_TEST_CASE( test_work )
{
  /// Adding the first edge should be one unit of work
  size_t capacity = 1;
  double window = .00000000001; //Make small window
  auto graph = new GraphType(capacity, window);

  UniformDestPort generator("192.168.0." +
    boost::lexical_cast<std::string>(1), 1);
  VastNetflow netflow = makeNetflow(0, generator.generate());

  size_t work = graph->addEdge(netflow);
  BOOST_CHECK_EQUAL(work, 1);

}

BOOST_AUTO_TEST_CASE( test_cleanup )
{
  /**
   * This tests cleaning up edges when the window has passed.
   */
  size_t capacity = 1;
  double window = .00000000001; //Make small window
  //double window = .1; //Make small window
  auto graph = new GraphType(capacity, window);

  int numThreads = 10;
  int numExamples = 10000;
  auto id = new std::atomic<int>(0);
  auto work = new std::atomic<size_t>(0);

  std::vector<std::thread> threads;
  for (int i = 0; i < numThreads; i++) {
    threads.push_back(std::thread([graph, id, i, numExamples, work]() {

      //UniformDestPort generator("192.168.0.1", 1);
      UniformDestPort generator("192.168.0." +
        boost::lexical_cast<std::string>(i), 1);

      for (int j =0; j < numExamples; j++) {
        VastNetflow netflow = makeNetflow(id->fetch_add(1),
                                          generator.generate());
        work->fetch_add(graph->addEdge(netflow));
      }

    }));
  }

  for (int i = 0; i < numThreads; i++) {
    threads[i].join();
  }

  size_t count = graph->countEdges();
  // Not sure how to make this exact, but almost all of the edges should
  // be deleted because the window is so small.
  std::cout << "count " << count << std::endl;
  BOOST_CHECK(count <  numThreads * 5);

  // Since the capacity is 1, all of the edges should go to the same list
  // in alle, so the process should be add edge (1 work unit) and delete old
  // edge (1 work unit).  So the total amount of work should be close to
  // 2 * number of edges added.
  //std::cout << "work " << work->load() << " 2 * numExamples * numThreads "
  //          << 2 * numExamples * numThreads << std::endl;
  //BOOST_CHECK(work->load() < 2 * numExamples * numThreads * 10);
  //BOOST_CHECK(work->load() > 2 * numExamples * numThreads * 10 - numThreads);
}

ext: cpp

max_stars_repo_name: dirkcgrunwald/SAM

max_issues_repo_name: dirkcgrunwald/SAM

max_forks_repo_name: dirkcgrunwald/SAM


text:
#include <pybind11/pybind11.h>

#include "baldr/rapidjson_utils.h"
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/property_tree/ptree.hpp>
#include <sstream>
#include <string>

#include "baldr/rapidjson_utils.h"
#include "midgard/logging.h"
#include "midgard/util.h"
#include "tyr/actor.h"

namespace vt = valhalla::tyr;
namespace {

// configuring multiple times is wasteful/ineffectual but not harmful
// TODO: make this threadsafe just in case its abused
const boost::property_tree::ptree configure(const std::string& config) {
  boost::property_tree::ptree pt;
  try {
    // parse the config and configure logging
    rapidjson::read_json(config, pt);

    boost::optional<boost::property_tree::ptree&> logging_subtree =
        pt.get_child_optional("mjolnir.logging");
    if (logging_subtree) {
      auto logging_config = valhalla::midgard::ToMap<const boost::property_tree::ptree&,
                                                     std::unordered_map<std::string, std::string>>(
          logging_subtree.get());
      valhalla::midgard::logging::Configure(logging_config);
    }
  } catch (...) { throw std::runtime_error("Failed to load config from: " + config); }

  return pt;
}
} // namespace

namespace py = pybind11;

PYBIND11_MODULE(python_valhalla, m) {
  py::class_<vt::actor_t>(m, "_Actor", "Valhalla Actor class")
      .def(py::init<>([](std::string config) { return vt::actor_t(configure(config), true); }))
      .def("route", [](vt::actor_t& self, std::string& req) { return self.route(req); },
           "Calculates a route.")
      .def("locate", [](vt::actor_t& self, std::string& req) { return self.locate(req); },
           "Provides information about nodes and edges.")
      .def("optimized_route",
           [](vt::actor_t& self, std::string& req) { return self.optimized_route(req); },
           "Optimizes the order of a set of waypoints by time.")
      .def(
          "matrix", [](vt::actor_t& self, std::string& req) { return self.matrix(req); },
          "Computes the time and distance between a set of locations and returns them as a matrix table.")
      .def("isochrone", [](vt::actor_t& self, std::string& req) { return self.isochrone(req); },
           "Calculates isochrones and isodistances.")
      .def("trace_route", [](vt::actor_t& self, std::string& req) { return self.trace_route(req); },
           "Map-matching for a set of input locations, e.g. from a GPS.")
      .def(
          "trace_attributes",
          [](vt::actor_t& self, std::string& req) { return self.trace_attributes(req); },
          "Returns detailed attribution along each portion of a route calculated from a set of input locations, e.g. from a GPS trace.")
      .def("height", [](vt::actor_t& self, std::string& req) { return self.height(req); },
           "Provides elevation data for a set of input geometries.")
      .def(
          "transit_available",
          [](vt::actor_t& self, std::string& req) { return self.transit_available(req); },
          "Lookup if transit stops are available in a defined radius around a set of input locations.")
      .def(
          "expansion", [](vt::actor_t& self, std::string& req) { return self.expansion(req); },
          "Returns all road segments which were touched by the routing algorithm during the graph traversal.")
      .def(
          "centroid", [](vt::actor_t& self, std::string& req) { return self.centroid(req); },
          "Returns routes from all the input locations to the minimum cost meeting point of those paths.")
      .def("status", [](vt::actor_t& self, std::string& req) { return self.status(req); },
           "Returns nothing or optionally details about Valhalla's configuration.");
}

max_stars_repo_name: Georepublic/valhalla

max_issues_repo_name: Georepublic/valhalla

max_forks_repo_name: Georepublic/valhalla


text:
#include <boost/format.hpp>
#include "tcp_connection_impl.hpp"

tcp_connection_impl::tcp_connection_impl(boost::asio::io_service& io_service, connections_manager& cm)
:tcp_connection(io_service), cm_(cm), read_timeout_(false), read_timer_(io_service),read_timer_duration(720)
{

}
tcp_connection_impl::~tcp_connection_impl()
{
	read_timer_.cancel();
}

void tcp_connection_impl::start(abstract_protocol_ptr protocol_impl )
{
	tcp_connection::start(protocol_impl);
	cm_.add(shared_from_this());
	protocol_impl_->tcp_connection_ip(remote_ip_, remote_port_);
	read_header();
	read_timer_.async_wait(boost::bind(&tcp_connection_impl::handle_timeout,this,
									   boost::asio::placeholders::error));
}

void tcp_connection_impl::read_header()
{
	size_t header_length = protocol_impl_->get_header_length();
	memory_buffer_ptr bp(new memory_buffer(header_length));
	boost::asio::async_read(socket_,
		boost::asio::buffer((void*)(bp.get()->data()), header_length),
		boost::bind(
		&tcp_connection_impl::handle_read_header, shared_from_this(),
		boost::asio::placeholders::error,  bp));
	read_timer_.expires_from_now(boost::posix_time::seconds(read_timer_duration));

}
void tcp_connection_impl::read_body(memory_buffer_ptr bp)
{
	size_t header_length = protocol_impl_->get_header_length();
	size_t total_length = protocol_impl_->get_total_length_from_header(bp);

	boost::asio::async_read(socket_,
		boost::asio::buffer((void*)(bp.get()->data() + header_length),
		total_length - header_length),
		boost::bind(&tcp_connection_impl::handle_read_body, shared_from_this(),
		boost::asio::placeholders::error, bp));
}
void tcp_connection_impl::write(void* data, std::size_t length)
{
	if(length == 0)
	{
		logger_log(__FUNCTION__, LEVEL_WARNING, "write 0 byte data is not recommended");
		return ;
	}
	boost::asio::async_write(socket_,
		boost::asio::buffer(data, length),
		boost::asio::transfer_at_least(length),
		boost::bind(&tcp_connection_impl::handle_write, shared_from_this(),
		boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void tcp_connection_impl::handle_timeout(const boost::system::error_code& e)
{
	if (e != boost::asio::error::operation_aborted)
	{
		read_timeout_ = true;
		logger_log(__FUNCTION__, LEVEL_ERROR, "read timeout...");
        /*call the functions under may call exceptional */
		//cm_.remove(shared_from_this());
		//force_shutdown();
	}
	else
	{
	}
	return;
}
void tcp_connection_impl::handle_read_header(const boost::system::error_code& error, memory_buffer_ptr bp)
{
	if (!error)
	{
		size_t header_length = protocol_impl_->get_header_length();
		size_t total_length = protocol_impl_->get_total_length_from_header(bp);
		if(total_length > header_length)
		{
			bp.get()->resize(total_length); // resize to the number of octets.
			read_body(bp);
		}
		else
		{
			//some commands only including header, no body, such as enquire_link
			protocol_impl_->add_to_in_queue(bp);
			read_header();
		}
	}
	else
	{
		logger_log(__FUNCTION__, LEVEL_INFO, "%s:%u disconnected from me, reason is %s.",
			remote_ip_.c_str(), remote_port_, boost::system::system_error(error).what());
		if (error != boost::asio::error::operation_aborted)
		{
			cm_.remove(shared_from_this());
		}
		else
		{
		}
	}
}

void tcp_connection_impl::handle_read_body(const boost::system::error_code& error, memory_buffer_ptr bp)
{
	if (!error)
	{
		protocol_impl_->add_to_in_queue(bp);
		//read another header
		read_header();
	}
	else
	{
		logger_log(__FUNCTION__, LEVEL_INFO, "%s:%u disconnected from me, reason is %s.",
			remote_ip_.c_str(), remote_port_, boost::system::system_error(error).what());

		if (error != boost::asio::error::operation_aborted)
		{
			cm_.remove(shared_from_this());
		}
		else
		{

		}
	}
}

void tcp_connection_impl::handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
	if (!error)
	{
	}
	else
	{
		logger_log(__FUNCTION__, LEVEL_INFO, "%s:%u disconnected from me, reason is %s.",
			remote_ip_.c_str(), remote_port_, boost::system::system_error(error).what());
		if (error != boost::asio::error::operation_aborted)
		{
			cm_.remove(shared_from_this());
		}
	}
}

void tcp_connection_impl::do_send()
{
	while(true)
	{
		memory_buffer_ptr bp;
		bool has = protocol_impl_->get_from_out_queue(bp);
		if(!has)
		{
			break;
		}
		const unsigned char* data = bp.get()->data();
		size_t total_length = bp.get()->size();
		size_t remain = total_length;
		size_t tmp_sent = 0;
		while(remain > 0)
		{
			size_t want_write = std::min(remain, (size_t)MTU);
			write((void*)data, want_write);
			data += want_write;
			remain -= want_write;
			tmp_sent += want_write;
			if(tmp_sent >= (size_t)send_buffer_size_)
			{
				boost::this_thread::sleep(boost::posix_time::milliseconds(20));
				tmp_sent = 0;
			}

		}
	}
}
void tcp_connection_impl::do_process()
{
	while(true)
	{
		memory_buffer_ptr bp;
		bool has = protocol_impl_->get_from_in_queue(bp);
		if(has)
		{
			protocol_impl_->process(bp);
			do_send();
		}
		else
		{
			break;
		}

	}

}

bool tcp_connection_impl::need_process()
{
	return protocol_impl_->need_process();
}
bool tcp_connection_impl::need_send()
{
	return protocol_impl_->need_send();
}

void tcp_connection_impl::force_remove()
{
	cm_.remove(shared_from_this());
}

max_stars_repo_name: dotphoenix/smppserver

max_issues_repo_name: dotphoenix/smppserver

max_forks_repo_name: dotphoenix/smppserver