<commit_before>/*
   Copyright (c) 2011, The Mineserver Project
   All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the The Mineserver Project nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef WIN32
#include <conio.h>
#include <WinSock2.h>
#else
#include <netinet/in.h>
#include <pwd.h>
#endif

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <string.h>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <string>
#include <cctype>

#include "tools.h"

void putSint64(uint8_t* buf, int64_t value)
{
  uint64_t nval = ntohll(value);
  memcpy(buf, &nval, 8);
}

void putSint32(uint8_t* buf, int32_t value)
{
  uint32_t nval = htonl(value);
  memcpy(buf, &nval, 4);
}

void putSint16(uint8_t* buf, int16_t value)
{
  short value2 = htons(value);
  memcpy(buf, &value2, 2);
}

void putFloat(uint8_t* buf, float value)
{
  uint32_t nval;
  memcpy(&nval, &value, 4);
  nval = htonl(nval);
  memcpy(buf, &nval, 4);
}

void putDouble(uint8_t* buf, double value)
{
  uint64_t nval;
  memcpy(&nval, &value, 8);
  nval = ntohll(nval);
  memcpy(buf, &nval, 8);
}

double getDouble(uint8_t* buf)
{
  double val;
  uint64_t ival = *reinterpret_cast<const int64_t*>(buf);
  ival = ntohll(ival);
  memcpy(&val, &ival, 8);
  return val;
}

float getFloat(uint8_t* buf)
{
  float val;
  int ival = ntohl(*reinterpret_cast<const int32_t*>(buf));
  memcpy(&val, &ival, 4);
  return val;
}

int64_t getSint64(uint8_t* buf)
{
  int64_t val;
  val = *reinterpret_cast<const int64_t*>(buf);
  val = ntohll(val);
  return val;
}

int32_t getSint32(uint8_t* buf)
{
  int val = ntohl(*reinterpret_cast<const int32_t*>(buf));
  return val;
}

int32_t getSint16(uint8_t* buf)
{
  short val = ntohs(*reinterpret_cast<const int16_t*>(buf));

  return val;
}

std::string base36_encode(int value)
{
  std::string output;
  my_itoa((int)abs(value), output, 36);
  if (value < 0)
  {
    output.insert(output.begin(), '-');
  }

  return output;
}

void my_itoa(int value, std::string& buf, int base)
{
  std::string hexarray("0123456789abcdefghijklmnopqrstuvwxyz");
  int i = 30;
  buf = "";

  if (!value)
  {
    buf = "0";
  }

  for (; value && i; --i, value /= base)
  {
    buf.insert(buf.begin(), (char)hexarray[value % base]);
  }
}

std::string strToLower(std::string temp)
{
  const int len = temp.length();

  for (int i = 0; i != len; ++i)
  {
    temp[i] = std::tolower(temp[i]);
  }

  return temp;
}

std::string dtos(double n)
{
  std::ostringstream result;
  result << n;
  return result.str();
}

std::string hash(std::string value)
{
  // Hash the player's name along with a secret to generate a unique hash for this player
  // Uses the DJB2 algorithm
  unsigned long hash = 5381;
  int c;

  char* cvalue = const_cast<char*>(value.c_str());

  while ((c = *cvalue++))
  {
    hash = ((hash << 5) + hash) + c;  /* hash * 33 + c */
  }

  std::ostringstream hashString;
  hashString << hash;

  return hashString.str();
}

std::string pathExpandUser(std::string path)
{
  std::string out;
  std::string user;
  size_t pos;

  if (path[0] != '~')
    return path;

  pos = path.find(PATH_SEPARATOR);
  if (pos == std::string::npos)
    pos = path.length();

  user = path.substr(1, pos - 1);
  if (!user.empty())
  {
#ifdef WIN32
    std::cerr << "~user notation is not implemented for this platform :P" << std::endl;
    return path;
#else
    struct passwd* entry = getpwnam(user.c_str());
    if (!entry)
    {
      std::cerr << user << ": no such user!" << std::endl;
      return path;
    }

    out += entry->pw_dir;
#endif
  }
  else
  {
    out.assign(getenv("HOME"));
  }

  out += '/';
  out += path.substr(pos + 1, path.length());
  return out;
}
<commit_msg>tools: use APPDATA env for pathExpandUser() on win32<commit_after>/*
   Copyright (c) 2011, The Mineserver Project
   All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the The Mineserver Project nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef WIN32
#include <conio.h>
#include <WinSock2.h>
#else
#include <netinet/in.h>
#include <pwd.h>
#endif

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <string.h>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <string>
#include <cctype>

#include "tools.h"

void putSint64(uint8_t* buf, int64_t value)
{
  uint64_t nval = ntohll(value);
  memcpy(buf, &nval, 8);
}

void putSint32(uint8_t* buf, int32_t value)
{
  uint32_t nval = htonl(value);
  memcpy(buf, &nval, 4);
}

void putSint16(uint8_t* buf, int16_t value)
{
  short value2 = htons(value);
  memcpy(buf, &value2, 2);
}

void putFloat(uint8_t* buf, float value)
{
  uint32_t nval;
  memcpy(&nval, &value, 4);
  nval = htonl(nval);
  memcpy(buf, &nval, 4);
}

void putDouble(uint8_t* buf, double value)
{
  uint64_t nval;
  memcpy(&nval, &value, 8);
  nval = ntohll(nval);
  memcpy(buf, &nval, 8);
}

double getDouble(uint8_t* buf)
{
  double val;
  uint64_t ival = *reinterpret_cast<const int64_t*>(buf);
  ival = ntohll(ival);
  memcpy(&val, &ival, 8);
  return val;
}

float getFloat(uint8_t* buf)
{
  float val;
  int ival = ntohl(*reinterpret_cast<const int32_t*>(buf));
  memcpy(&val, &ival, 4);
  return val;
}

int64_t getSint64(uint8_t* buf)
{
  int64_t val;
  val = *reinterpret_cast<const int64_t*>(buf);
  val = ntohll(val);
  return val;
}

int32_t getSint32(uint8_t* buf)
{
  int val = ntohl(*reinterpret_cast<const int32_t*>(buf));
  return val;
}

int32_t getSint16(uint8_t* buf)
{
  short val = ntohs(*reinterpret_cast<const int16_t*>(buf));

  return val;
}

std::string base36_encode(int value)
{
  std::string output;
  my_itoa((int)abs(value), output, 36);
  if (value < 0)
  {
    output.insert(output.begin(), '-');
  }

  return output;
}

void my_itoa(int value, std::string& buf, int base)
{
  std::string hexarray("0123456789abcdefghijklmnopqrstuvwxyz");
  int i = 30;
  buf = "";

  if (!value)
  {
    buf = "0";
  }

  for (; value && i; --i, value /= base)
  {
    buf.insert(buf.begin(), (char)hexarray[value % base]);
  }
}

std::string strToLower(std::string temp)
{
  const int len = temp.length();

  for (int i = 0; i != len; ++i)
  {
    temp[i] = std::tolower(temp[i]);
  }

  return temp;
}

std::string dtos(double n)
{
  std::ostringstream result;
  result << n;
  return result.str();
}

std::string hash(std::string value)
{
  // Hash the player's name along with a secret to generate a unique hash for this player
  // Uses the DJB2 algorithm
  unsigned long hash = 5381;
  int c;

  char* cvalue = const_cast<char*>(value.c_str());

  while ((c = *cvalue++))
  {
    hash = ((hash << 5) + hash) + c;  /* hash * 33 + c */
  }

  std::ostringstream hashString;
  hashString << hash;

  return hashString.str();
}

std::string pathExpandUser(std::string path)
{
  std::string out;
  std::string user;
  size_t pos;

  if (path[0] != '~')
    return path;

  pos = path.find(PATH_SEPARATOR);
  if (pos == std::string::npos)
    pos = path.length();

  user = path.substr(1, pos - 1);
  if (!user.empty())
  {
#ifdef WIN32
    std::cerr << "~user notation is not implemented for this platform :P" << std::endl;
    return path;
#else
    struct passwd* entry = getpwnam(user.c_str());
    if (!entry)
    {
      std::cerr << user << ": no such user!" << std::endl;
      return path;
    }

    out += entry->pw_dir;
#endif
  }
  else
  {
#ifdef WIN32
#define ENV_HOME "APPDATA"
#else
#define ENV_HOME "HOME"
#endif
    out.assign(getenv(ENV_HOME));
  }

  out += '/';
  out += path.substr(pos + 1, path.length());
  return out;
}
<|endoftext|>


<commit_before>// Halide tutorial lesson 12.

// This lesson demonstrates how to use Halide to run code on a GPU.

// On linux, you can compile and run it like so:
// g++ lesson_12*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_12
// LD_LIBRARY_PATH=../bin ./lesson_12

// On os x:
// g++ lesson_12*.cpp -g -I ../include -L ../bin -lHalide -lpng -o lesson_12
// DYLD_LIBRARY_PATH=../bin ./lesson_12

#include <Halide.h>
#include <stdio.h>
using namespace Halide;

// Include some support code for loading pngs.
#include "image_io.h"

// Include a clock to do performance testing.
#include "clock.h"

// Define some Vars to use.
Var x, y, c, i;

// We're going to want to schedule a pipeline in several ways, so we
// define the pipeline in a class so that we can recreate it several
// times with different schedules.
class Pipeline {
public:
    Func lut, padded, padded16, sharpen, curved;
    Image<uint8_t> input;

    Pipeline(Image<uint8_t> in) : input(in) {
        // For this lesson, we'll use a two-stage pipeline that sharpens
        // and then applies a look-up-table (LUT).

        // First we'll define the LUT. It will be a gamma curve.

        lut(i) = cast<uint8_t>(clamp(pow(i / 255.0f, 1.2f) * 255.0f, 0, 255));

        // Augment the input with a boundary condition.
        padded(x, y, c) = input(clamp(x, 0, input.width()-1),
                                clamp(y, 0, input.height()-1), c);

        // Cast it to 16-bit to do the math.
        padded16(x, y, c) = cast<uint16_t>(padded(x, y, c));

        // Next we sharpen it with a five-tap filter.
        sharpen(x, y, c) = (padded16(x, y, c) * 2-
                            (padded16(x - 1, y, c) +
                             padded16(x, y - 1, c) +
                             padded16(x + 1, y, c) +
                             padded16(x, y + 1, c)) / 4);

        // Then apply the LUT.
        curved(x, y, c) = lut(sharpen(x, y, c));
    }

    // Now we define methods that give our pipeline several different
    // schedules.
    void schedule_for_cpu() {
        // Compute the look-up-table ahead of time.
        lut.compute_root();

        // Compute color channels innermost. Promise that there will
        // be three of them and unroll across them.
        curved.reorder(c, x, y)
              .bound(c, 0, 3)
              .unroll(c);

        // Look-up-tables don't vectorize well, so just parallelize
        // curved in slices of 16 scanlines.
        Var yo, yi;
        curved.split(y, yo, yi, 16)
              .parallel(yo);

        // Compute sharpen as needed per scanline of curved, reusing
        // previous values computed within the same strip of 16
        // scanlines.
        sharpen.store_at(curved, yo)
               .compute_at(curved, yi);

        // Vectorize the sharpen. It's 16-bit so we'll vectorize it 8-wide.
        sharpen.vectorize(x, 8);

        // Compute the padded input at the same granularity as the
        // sharpen. We'll leave the cast to 16-bit inlined into
        // sharpen.
        padded.store_at(curved, yo)
              .compute_at(curved, yi);

        // Also vectorize the padding. It's 8-bit, so we'll vectorize
        // 16-wide.
        padded.vectorize(x, 16);

        // JIT-compile the pipeline for the CPU.
        curved.compile_jit();
    }

    // Now a schedule that uses CUDA or OpenCL.
    void schedule_for_gpu() {
        // We make the decision about whether to use the GPU for each
        // Func independently. If you have one Func computed on the
        // CPU, and the next computed on the GPU, Halide will do the
        // copy-to-gpu under the hood. For this pipeline, there's no
        // reason to use the CPU for any of the stages. Halide will
        // copy the input image to the GPU the first time we run the
        // pipeline, and leave it there to reuse on subsequent runs.

        // As before, we'll compute the LUT once at the start of the
        // pipeline.
        lut.compute_root();

        // Let's compute the look-up-table using the GPU in 16-wide
        // one-dimensional thread blocks. First we split the index
        // into blocks of size 16:
        Var block, thread;
        lut.split(i, block, thread, 16);
        // Then we tell cuda that our Vars 'block' and 'thread'
        // correspond to CUDA's notions of blocks and threads, or
        // OpenCL's notions of thread groups and threads.
        lut.gpu_blocks(block)
           .gpu_threads(thread);

        // This is a very common scheduling pattern on the GPU, so
        // there's a shorthand for it:

        // lut.gpu_tile(i, 16);

        // Func::gpu_tile method is similar to Func::tile, except that
        // it also specifies that the tile coordinates correspond to
        // GPU blocks, and the coordinates within each tile correspond
        // to GPU threads.

        // Compute color channels innermost. Promise that there will
        // be three of them and unroll across them.
        curved.reorder(c, x, y)
              .bound(c, 0, 3)
              .unroll(c);

        // Compute curved in 2D 8x8 tiles using the GPU.
        curved.gpu_tile(x, y, 8, 8);

        // This is equivalent to:
        // curved.tile(x, y, xo, yo, xi, yi, 8, 8)
        //       .gpu_blocks(xo, yo)
        //       .gpu_threads(xi, yi);

        // We'll leave sharpen as inlined into curved.

        // Compute the padded input as needed per GPU block, storing the
        // intermediate result in shared memory. Var::gpu_blocks, and
        // Var::gpu_threads exist to help you schedule producers within
        // GPU threads and blocks.
        padded.compute_at(curved, Var::gpu_blocks());

        // Use the GPU threads for the x and y coordinates of the
        // padded input.
        padded.gpu_threads(x, y);

        // JIT-compile the pipeline for the GPU. CUDA or OpenCL are
        // not enabled by default. We have to construct a Target
        // object, enable one of them, and then pass that target
        // object to compile_jit. Otherwise your CPU will very slowly
        // pretend it's a GPU, and use one thread per output pixel.

        // Start with a target suitable for the machine you're running
        // this on.
        Target target = get_host_target();

        // Then enable OpenCL or CUDA.

        // We'll enable OpenCL here, because it tends to give better
        // performance than CUDA, even with NVidia's drivers, because
        // NVidia's open source LLVM backend doesn't seem to do all
        // the same optimizations their proprietary compiler does.
        target.set_feature(Target::OpenCL);

        // Uncomment the next line and comment out the line above to
        // try CUDA instead.
        // target.set_feature(Target::CUDA);

        // If you want to see all of the OpenCL or CUDA API calls done
        // by the pipeline, you can also enable the Debug
        // flag. This is helpful for figuring out which stages are
        // slow, or when CPU -> GPU copies happen. It hurts
        // performance though, so we'll leave it commented out.
        // target.set_feature(Target::Debug);

        curved.compile_jit(target);
    }

    void test_performance() {
        // Test the performance of the scheduled Pipeline.

        // If we realize curved into a Halide::Image, that will
        // unfairly penalize GPU performance by including a GPU->CPU
        // copy in every run. Halide::Image objects always exist on
        // the CPU.

        // Halide::Buffer, however, represents a buffer that may
        // exist on either CPU or GPU or both.
        Buffer output(UInt(8), input.width(), input.height(), input.channels());

        // Run the filter once to initialize any GPU runtime state.
        curved.realize(output);

        // Now take the best of 3 runs for timing.
        double best_time;
        for (int i = 0; i < 3; i++) {

            double t1 = current_time();

            // Run the filter 100 times.
            for (int j = 0; j < 100; j++) {
                curved.realize(output);
            }

            // Force any GPU code to finish by copying the buffer back to the CPU.
            output.copy_to_host();

            double t2 = current_time();

            double elapsed = (t2 - t1)/100;
            if (i == 0 || elapsed < best_time) {
                best_time = elapsed;
            }
        }

        printf("%1.4f milliseconds\n", best_time);
    }

    void test_correctness(Image<uint8_t> reference_output) {
        Image<uint8_t> output = curved.realize(input.width(), input.height(), input.channels());

        // Check against the reference output.
        for (int c = 0; c < input.channels(); c++) {
            for (int y = 0; y < input.height(); y++) {
                for (int x = 0; x < input.width(); x++) {
                    if (output(x, y, c) != reference_output(x, y, c)) {
                        printf("Mismatch between output (%d) and "
                               "reference output (%d) at %d, %d, %d\n",
                               output(x, y, c),
                               reference_output(x, y, c),
                               x, y, c);
                    }
                }
            }
        }

    }
};

bool have_opencl();

int main(int argc, char **argv) {
    // Load an input image.
    Image<uint8_t> input = load<uint8_t>("images/rgb.png");

    // Allocated an image that will store the correct output
    Image<uint8_t> reference_output(input.width(), input.height(), input.channels());

    printf("Testing performance on CPU:\n");
    Pipeline p1(input);
    p1.schedule_for_cpu();
    p1.test_performance();
    p1.curved.realize(reference_output);

    if (have_opencl()) {
        printf("Testing performance on GPU:\n");
        Pipeline p2(input);
        p2.schedule_for_gpu();
        p2.test_performance();
        p2.test_correctness(reference_output);
    } else {
        printf("Not testing performance on GPU, because I can't find the opencl library\n");
    }

    return 0;
}

// A helper function to check if OpenCL seems to exist on this machine.

#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

bool have_opencl() {
#ifdef _WIN32
    return LoadLibrary("opengl.dll") != NULL;
#elif __APPLE__
    return dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_LAZY) != NULL;
#else
    return dlopen("libOpenCL.so", RTLD_LAZY) != NULL;
#endif
}
<commit_msg>Bail from tutorial on first error<commit_after>// Halide tutorial lesson 12.

// This lesson demonstrates how to use Halide to run code on a GPU.

// On linux, you can compile and run it like so:
// g++ lesson_12*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_12
// LD_LIBRARY_PATH=../bin ./lesson_12

// On os x:
// g++ lesson_12*.cpp -g -I ../include -L ../bin -lHalide -lpng -o lesson_12
// DYLD_LIBRARY_PATH=../bin ./lesson_12

#include <Halide.h>
#include <stdio.h>
using namespace Halide;

// Include some support code for loading pngs.
#include "image_io.h"

// Include a clock to do performance testing.
#include "clock.h"

// Define some Vars to use.
Var x, y, c, i;

// We're going to want to schedule a pipeline in several ways, so we
// define the pipeline in a class so that we can recreate it several
// times with different schedules.
class Pipeline {
public:
    Func lut, padded, padded16, sharpen, curved;
    Image<uint8_t> input;

    Pipeline(Image<uint8_t> in) : input(in) {
        // For this lesson, we'll use a two-stage pipeline that sharpens
        // and then applies a look-up-table (LUT).

        // First we'll define the LUT. It will be a gamma curve.

        lut(i) = cast<uint8_t>(clamp(pow(i / 255.0f, 1.2f) * 255.0f, 0, 255));

        // Augment the input with a boundary condition.
        padded(x, y, c) = input(clamp(x, 0, input.width()-1),
                                clamp(y, 0, input.height()-1), c);

        // Cast it to 16-bit to do the math.
        padded16(x, y, c) = cast<uint16_t>(padded(x, y, c));

        // Next we sharpen it with a five-tap filter.
        sharpen(x, y, c) = (padded16(x, y, c) * 2-
                            (padded16(x - 1, y, c) +
                             padded16(x, y - 1, c) +
                             padded16(x + 1, y, c) +
                             padded16(x, y + 1, c)) / 4);

        // Then apply the LUT.
        curved(x, y, c) = lut(sharpen(x, y, c));
    }

    // Now we define methods that give our pipeline several different
    // schedules.
    void schedule_for_cpu() {
        // Compute the look-up-table ahead of time.
        lut.compute_root();

        // Compute color channels innermost. Promise that there will
        // be three of them and unroll across them.
        curved.reorder(c, x, y)
              .bound(c, 0, 3)
              .unroll(c);

        // Look-up-tables don't vectorize well, so just parallelize
        // curved in slices of 16 scanlines.
        Var yo, yi;
        curved.split(y, yo, yi, 16)
              .parallel(yo);

        // Compute sharpen as needed per scanline of curved, reusing
        // previous values computed within the same strip of 16
        // scanlines.
        sharpen.store_at(curved, yo)
               .compute_at(curved, yi);

        // Vectorize the sharpen. It's 16-bit so we'll vectorize it 8-wide.
        sharpen.vectorize(x, 8);

        // Compute the padded input at the same granularity as the
        // sharpen. We'll leave the cast to 16-bit inlined into
        // sharpen.
        padded.store_at(curved, yo)
              .compute_at(curved, yi);

        // Also vectorize the padding. It's 8-bit, so we'll vectorize
        // 16-wide.
        padded.vectorize(x, 16);

        // JIT-compile the pipeline for the CPU.
        curved.compile_jit();
    }

    // Now a schedule that uses CUDA or OpenCL.
    void schedule_for_gpu() {
        // We make the decision about whether to use the GPU for each
        // Func independently. If you have one Func computed on the
        // CPU, and the next computed on the GPU, Halide will do the
        // copy-to-gpu under the hood. For this pipeline, there's no
        // reason to use the CPU for any of the stages. Halide will
        // copy the input image to the GPU the first time we run the
        // pipeline, and leave it there to reuse on subsequent runs.

        // As before, we'll compute the LUT once at the start of the
        // pipeline.
        lut.compute_root();

        // Let's compute the look-up-table using the GPU in 16-wide
        // one-dimensional thread blocks. First we split the index
        // into blocks of size 16:
        Var block, thread;
        lut.split(i, block, thread, 16);
        // Then we tell cuda that our Vars 'block' and 'thread'
        // correspond to CUDA's notions of blocks and threads, or
        // OpenCL's notions of thread groups and threads.
        lut.gpu_blocks(block)
           .gpu_threads(thread);

        // This is a very common scheduling pattern on the GPU, so
        // there's a shorthand for it:

        // lut.gpu_tile(i, 16);

        // Func::gpu_tile method is similar to Func::tile, except that
        // it also specifies that the tile coordinates correspond to
        // GPU blocks, and the coordinates within each tile correspond
        // to GPU threads.

        // Compute color channels innermost. Promise that there will
        // be three of them and unroll across them.
        curved.reorder(c, x, y)
              .bound(c, 0, 3)
              .unroll(c);

        // Compute curved in 2D 8x8 tiles using the GPU.
        curved.gpu_tile(x, y, 8, 8);

        // This is equivalent to:
        // curved.tile(x, y, xo, yo, xi, yi, 8, 8)
        //       .gpu_blocks(xo, yo)
        //       .gpu_threads(xi, yi);

        // We'll leave sharpen as inlined into curved.

        // Compute the padded input as needed per GPU block, storing the
        // intermediate result in shared memory. Var::gpu_blocks, and
        // Var::gpu_threads exist to help you schedule producers within
        // GPU threads and blocks.
        padded.compute_at(curved, Var::gpu_blocks());

        // Use the GPU threads for the x and y coordinates of the
        // padded input.
        padded.gpu_threads(x, y);

        // JIT-compile the pipeline for the GPU. CUDA or OpenCL are
        // not enabled by default. We have to construct a Target
        // object, enable one of them, and then pass that target
        // object to compile_jit. Otherwise your CPU will very slowly
        // pretend it's a GPU, and use one thread per output pixel.

        // Start with a target suitable for the machine you're running
        // this on.
        Target target = get_host_target();

        // Then enable OpenCL or CUDA.

        // We'll enable OpenCL here, because it tends to give better
        // performance than CUDA, even with NVidia's drivers, because
        // NVidia's open source LLVM backend doesn't seem to do all
        // the same optimizations their proprietary compiler does.
        target.set_feature(Target::OpenCL);

        // Uncomment the next line and comment out the line above to
        // try CUDA instead.
        // target.set_feature(Target::CUDA);

        // If you want to see all of the OpenCL or CUDA API calls done
        // by the pipeline, you can also enable the Debug
        // flag. This is helpful for figuring out which stages are
        // slow, or when CPU -> GPU copies happen. It hurts
        // performance though, so we'll leave it commented out.
        // target.set_feature(Target::Debug);

        curved.compile_jit(target);
    }

    void test_performance() {
        // Test the performance of the scheduled Pipeline.

        // If we realize curved into a Halide::Image, that will
        // unfairly penalize GPU performance by including a GPU->CPU
        // copy in every run. Halide::Image objects always exist on
        // the CPU.

        // Halide::Buffer, however, represents a buffer that may
        // exist on either CPU or GPU or both.
        Buffer output(UInt(8), input.width(), input.height(), input.channels());

        // Run the filter once to initialize any GPU runtime state.
        curved.realize(output);

        // Now take the best of 3 runs for timing.
        double best_time;
        for (int i = 0; i < 3; i++) {

            double t1 = current_time();

            // Run the filter 100 times.
            for (int j = 0; j < 100; j++) {
                curved.realize(output);
            }

            // Force any GPU code to finish by copying the buffer back to the CPU.
            output.copy_to_host();

            double t2 = current_time();

            double elapsed = (t2 - t1)/100;
            if (i == 0 || elapsed < best_time) {
                best_time = elapsed;
            }
        }

        printf("%1.4f milliseconds\n", best_time);
    }

    void test_correctness(Image<uint8_t> reference_output) {
        Image<uint8_t> output = curved.realize(input.width(), input.height(), input.channels());

        // Check against the reference output.
        for (int c = 0; c < input.channels(); c++) {
            for (int y = 0; y < input.height(); y++) {
                for (int x = 0; x < input.width(); x++) {
                    if (output(x, y, c) != reference_output(x, y, c)) {
                        printf("Mismatch between output (%d) and "
                               "reference output (%d) at %d, %d, %d\n",
                               output(x, y, c),
                               reference_output(x, y, c),
                               x, y, c);
                        exit(0);
                    }
                }
            }
        }

    }
};

bool have_opencl();

int main(int argc, char **argv) {
    // Load an input image.
    Image<uint8_t> input = load<uint8_t>("images/rgb.png");

    // Allocated an image that will store the correct output
    Image<uint8_t> reference_output(input.width(), input.height(), input.channels());

    printf("Testing performance on CPU:\n");
    Pipeline p1(input);
    p1.schedule_for_cpu();
    p1.test_performance();
    p1.curved.realize(reference_output);

    if (have_opencl()) {
        printf("Testing performance on GPU:\n");
        Pipeline p2(input);
        p2.schedule_for_gpu();
        p2.test_performance();
        p2.test_correctness(reference_output);
    } else {
        printf("Not testing performance on GPU, because I can't find the opencl library\n");
    }

    return 0;
}

// A helper function to check if OpenCL seems to exist on this machine.

#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

bool have_opencl() {
#ifdef _WIN32
    return LoadLibrary("opengl.dll") != NULL;
#elif __APPLE__
    return dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_LAZY) != NULL;
#else
    return dlopen("libOpenCL.so", RTLD_LAZY) != NULL;
#endif
}
<|endoftext|>


<commit_before>#include <iostream>
#include <ctime>
#include <cstring>
#include <vector>

#include <TRandom2.h>
#include <TMath.h>
#include <TStopwatch.h>

#include <TApplication.h>
#include <TCanvas.h>
#include <TH2F.h>
#include <TGraph.h>
#include <TLegend.h>
#include <TAxis.h>

using namespace std;

const int npass0 = 200000;
const int maxint = 100;//20;
const int minsize = 10;//20;
const int maxsize = 1000000;//500;
const int increment = 10;  // increment factor (multiplicative)
const int arraysize = std::log10(maxsize/minsize)+1;

bool showGraphics = false;
bool verbose = false;

template <typename T> bool testBinarySearch(const int n, double* tTMath, double* tStd)
{
   std::cout << "Testing size n = " << n <<  "\t(Time / call in microsec.) " << std::endl;

   vector<T> k(n);
   TStopwatch t;
   TRandom2 r( time( 0 ) );
   for ( Int_t i = 0; i < n; i++) {
      k[i] = (T) r.Integer( maxint );
   }

   std::sort(k.begin(), k.end());

   int npass = npass0/std::log10(double(10*n/minsize));

   int s1 = 0;
   t.Start();
   for (int j = 0; j < npass; ++j) {
      for ( T elem = 0; elem < maxint; ++elem ) {
         Long_t index = TMath::BinarySearch((Long_t) n, &k[0], elem);
         s1 += index;
      }
   }
   t.Stop();
   *tTMath = t.RealTime()/npass*1.E6;
   cout << "TMath::BinarySearch time :\t " << *tTMath << endl;
//   cout << "sum " << s1 << endl;

   int s2 = 0;
   t.Start();
   for (int j = 0; j < npass; ++j) {
      for ( T elem = 0; elem < maxint; ++elem ) {
         T* pind;
         pind = std::lower_bound(&k[0], &k[n], elem);
         Long_t index2 = ((*pind == elem)? (pind - &k[0]): ( pind - &k[0] - 1));
         s2+= index2;
      }
   }
   t.Stop();
   *tStd = t.RealTime()/double(npass)*1.E6;
   std::cout << "std::binary_search time:\t " << *tStd << '\n' << std::endl;
//   cout << "sum " << s2 << endl;
   if (s1 != s2) {
      Error("testBinarySearch","Different results obtained for size n = %d  - s1 = %d s2 = %d",n,s1,s2);
      return false;
   }
   return true;

}

bool binarySearchTime()
{
   vector<double> tM( arraysize );
   vector<double> tS( arraysize );
   vector<double> index( arraysize );

   //cout << (maxsize-minsize)/10 + 1 << endl;

   bool ok = true;
   int j = 0; int i = minsize;
   while ( i <= maxsize)
   {
      ok &= testBinarySearch<Double_t>(i, &tM[j], &tS[j]);
      index[j] = i;
      j++;
      i *= increment;
   }
   int ntest = j;

   if (verbose) {
      cout << " TMATH - time  ---  std time " << std::endl;
      for ( int i = 0; i < ntest; ++i) {
         cout << " size = " << index[i] << " :  " << tM[i] << ' ' << tS[i] << endl;
      }
   }

   if ( showGraphics )
   {
      TCanvas* c1 = new TCanvas("c1", "Comparision of Searching Time", 600, 400);
      c1->SetLogx(true);

      TGraph* gM = new TGraph(arraysize, &index[0], &tM[0]);
      gM->SetLineColor(2);
      gM->SetLineWidth(3);
      gM->SetMarkerStyle(20);
      gM->SetTitle("TMath::BinarySearch()");
      gM->Draw("ALP");

      TGraph* gS = new TGraph(arraysize, &index[0], &tS[0]);
      gS->SetLineColor(3);
      gS->SetLineWidth(3);
      gS->SetMarkerStyle(20);
      gS->SetTitle("std::binary_search()");
      gS->Draw("SAME");

      TLegend* legend = new TLegend(0.15,0.72,0.4,0.86);
      legend->AddEntry(gM, "TMath::BinarySearch()");
      legend->AddEntry(gS, "std::binary_search()");
      legend->Draw();

      gM->SetTitle("Comparision of Searching Time");
      gM->GetXaxis()->SetTitle("Array Size");
      gM->GetYaxis()->SetTitle("Time");

      c1->Show();
   }

   if (ok)
      cout << "Test done!" << endl;
   else
      cout << "Error: Test Failed!" << endl;
   return ok;
}

int main(int argc, char **argv)
{

  // Parse command line arguments
  for (Int_t i=1 ;  i<argc ; i++) {
     std::string arg = argv[i] ;
     if (arg == "-g") {
      showGraphics = true;
     }
     if (arg == "-v") {
      showGraphics = true;
      verbose = true;
     }
     if (arg == "-h") {
        cerr << "Usage: " << argv[0] << " [-g] [-v]\n";
        cerr << "  where:\n";
        cerr << "     -g : graphics mode\n";
        cerr << "     -v : verbose  mode";
        cerr << endl;
        return -1;
     }
   }

   TApplication* theApp = 0;
   if ( showGraphics )
      theApp = new TApplication("App",&argc,argv);

   bool ok = binarySearchTime();

   if ( showGraphics )
   {
      theApp->Run();
      delete theApp;
      theApp = 0;
   }

   return (ok) ? 0 : 1;
}
<commit_msg>Another fix for Windows<commit_after>#include <iostream>
#include <ctime>
#include <cstring>
#include <vector>

#include <TRandom2.h>
#include <TMath.h>
#include <TStopwatch.h>

#include <TApplication.h>
#include <TCanvas.h>
#include <TH2F.h>
#include <TGraph.h>
#include <TLegend.h>
#include <TAxis.h>

using namespace std;

const int npass0 = 200000;
const int maxint = 100;//20;
const int minsize = 10;//20;
const int maxsize = 1000000;//500;
const int increment = 10;  // increment factor (multiplicative)
const int arraysize = int(std::log10(double(maxsize/minsize)))+1;

bool showGraphics = false;
bool verbose = false;

template <typename T> bool testBinarySearch(const int n, double* tTMath, double* tStd)
{
   std::cout << "Testing size n = " << n <<  "\t(Time / call in microsec.) " << std::endl;

   vector<T> k(n);
   TStopwatch t;
   TRandom2 r( time( 0 ) );
   for ( Int_t i = 0; i < n; i++) {
      k[i] = (T) r.Integer( maxint );
   }

   std::sort(k.begin(), k.end());

   int npass = npass0/std::log10(double(10*n/minsize));

   int s1 = 0;
   t.Start();
   for (int j = 0; j < npass; ++j) {
      for ( T elem = 0; elem < maxint; ++elem ) {
         Long_t index = TMath::BinarySearch((Long_t) n, &k[0], elem);
         s1 += index;
      }
   }
   t.Stop();
   *tTMath = t.RealTime()/npass*1.E6;
   cout << "TMath::BinarySearch time :\t " << *tTMath << endl;
//   cout << "sum " << s1 << endl;

   int s2 = 0;
   t.Start();
   for (int j = 0; j < npass; ++j) {
      for ( T elem = 0; elem < maxint; ++elem ) {
         T* pind;
         pind = std::lower_bound(&k[0], &k[n], elem);
         Long_t index2 = ((*pind == elem)? (pind - &k[0]): ( pind - &k[0] - 1));
         s2+= index2;
      }
   }
   t.Stop();
   *tStd = t.RealTime()/double(npass)*1.E6;
   std::cout << "std::binary_search time:\t " << *tStd << '\n' << std::endl;
//   cout << "sum " << s2 << endl;
   if (s1 != s2) {
      Error("testBinarySearch","Different results obtained for size n = %d  - s1 = %d s2 = %d",n,s1,s2);
      return false;
   }
   return true;

}

bool binarySearchTime()
{
   vector<double> tM( arraysize );
   vector<double> tS( arraysize );
   vector<double> index( arraysize );

   //cout << (maxsize-minsize)/10 + 1 << endl;

   bool ok = true;
   int j = 0; int i = minsize;
   while ( i <= maxsize)
   {
      ok &= testBinarySearch<Double_t>(i, &tM[j], &tS[j]);
      index[j] = i;
      j++;
      i *= increment;
   }
   int ntest = j;

   if (verbose) {
      cout << " TMATH - time  ---  std time " << std::endl;
      for ( int i = 0; i < ntest; ++i) {
         cout << " size = " << index[i] << " :  " << tM[i] << ' ' << tS[i] << endl;
      }
   }

   if ( showGraphics )
   {
      TCanvas* c1 = new TCanvas("c1", "Comparision of Searching Time", 600, 400);
      c1->SetLogx(true);

      TGraph* gM = new TGraph(arraysize, &index[0], &tM[0]);
      gM->SetLineColor(2);
      gM->SetLineWidth(3);
      gM->SetMarkerStyle(20);
      gM->SetTitle("TMath::BinarySearch()");
      gM->Draw("ALP");

      TGraph* gS = new TGraph(arraysize, &index[0], &tS[0]);
      gS->SetLineColor(3);
      gS->SetLineWidth(3);
      gS->SetMarkerStyle(20);
      gS->SetTitle("std::binary_search()");
      gS->Draw("SAME");

      TLegend* legend = new TLegend(0.15,0.72,0.4,0.86);
      legend->AddEntry(gM, "TMath::BinarySearch()");
      legend->AddEntry(gS, "std::binary_search()");
      legend->Draw();

      gM->SetTitle("Comparision of Searching Time");
      gM->GetXaxis()->SetTitle("Array Size");
      gM->GetYaxis()->SetTitle("Time");

      c1->Show();
   }

   if (ok)
      cout << "Test done!" << endl;
   else
      cout << "Error: Test Failed!" << endl;
   return ok;
}

int main(int argc, char **argv)
{

  // Parse command line arguments
  for (Int_t i=1 ;  i<argc ; i++) {
     std::string arg = argv[i] ;
     if (arg == "-g") {
      showGraphics = true;
     }
     if (arg == "-v") {
      showGraphics = true;
      verbose = true;
     }
     if (arg == "-h") {
        cerr << "Usage: " << argv[0] << " [-g] [-v]\n";
        cerr << "  where:\n";
        cerr << "     -g : graphics mode\n";
        cerr << "     -v : verbose  mode";
        cerr << endl;
        return -1;
     }
   }

   TApplication* theApp = 0;
   if ( showGraphics )
      theApp = new TApplication("App",&argc,argv);

   bool ok = binarySearchTime();

   if ( showGraphics )
   {
      theApp->Run();
      delete theApp;
      theApp = 0;
   }

   return (ok) ? 0 : 1;
}
<|endoftext|>


<commit_before>/* <x0/mod_vhost_basic.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/plugin.hpp>
#include <x0/server.hpp>
#include <x0/request.hpp>
#include <x0/response.hpp>
#include <x0/listener.hpp>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

/**
 * \ingroup plugins
 * \brief provides a basic config-file based virtual hosting facility.
 *
 *

 * -- example configuration
 *
 * BindAddress = '0::0';             -- default bind address
 * Listen = 80;                      -- default listening port
 * DefaultHost = 'www.example.com';  -- default vhost to choose when we receive an unknown Host-request-header.
 *
 * Hosts = {
 *     ['www.example.com'] = {
 *         ServerAliases = { 'www.example.net', 'example.com', 'example.net' };
 *         DocumentRoot = '/var/www/example.com/htdocs';
 *     };
 *     ['localhost:8080'] = {
 *         DocumentRoot = '/var/www/example.com/htdocs';
 *         BindAddress = 'localhost';
 *
 *         Secure = true;
 *         CertFile = 'cert.pem';
 *         KeyFile = 'key.pem';
 *         TrustFile = 'ca.pem';
 *         CrlFile = 'crl.pem';
 *     };
 * };
 *

 */
class vhost_basic_plugin :
	public x0::plugin
{
private:
	struct vhost_config
	{
		std::string name;
		std::string document_root;
		std::string bindaddress;
	};

	x0::server::request_parse_hook::connection c;
	std::map<std::string, vhost_config *> mappings; // [hostname:port] -> vhost_config
	std::map<int, vhost_config *> default_hosts; // [port] -> vhost_config

public:
	vhost_basic_plugin(x0::server& srv, const std::string& name) :
		x0::plugin(srv, name)
	{
		using namespace std::placeholders;

		c = server_.resolve_document_root.connect(std::bind(&vhost_basic_plugin::resolve_document_root, this, _1));

		server_.register_cvar_host("DocumentRoot", std::bind(&vhost_basic_plugin::setup_docroot, this, _1, _2), 0);
		server_.register_cvar_host("Default", std::bind(&vhost_basic_plugin::setup_default, this, _1, _2), 1);
		server_.register_cvar_host("BindAddress", std::bind(&vhost_basic_plugin::setup_bindaddress, this, _1, _2), 1);
		server_.register_cvar_host("Aliases", std::bind(&vhost_basic_plugin::setup_aliases, this, _1, _2), 1);
	}

	~vhost_basic_plugin()
	{
		server_.resolve_document_root.disconnect(c);
	}

	void setup_docroot(const x0::settings_value& cvar, const std::string& hostid)
	{
		std::string document_root = cvar.as<std::string>();

		if (document_root.empty())
		{
			char msg[256];
			std::snprintf(msg, sizeof(msg),
				"vhost_basic[%s]: document root must not be empty.",
				hostid.c_str());

			throw std::runtime_error(msg);
		}

		if (document_root[0] != '/')
		{
			log(x0::severity::warn,
				"vhost_basic[%s]: document root should be an absolute path: '%s'",
				hostid.c_str(), document_root.c_str());
		}

		vhost_config *cfg = server_.create_context<vhost_config>(this, hostid);
		cfg->name = hostid;
		cfg->document_root = document_root;

		// register primary [hostname:port]
		if (!register_vhost(hostid, cfg))
		{
			char msg[1024];
			snprintf(msg, sizeof(msg), "Server name '%s' already in use.", hostid.c_str());
			throw std::runtime_error(msg);
		}
	}

	void setup_bindaddress(const x0::settings_value& cvar, const std::string& hostid)
	{
		int port = x0::extract_port_from_hostid(hostid);
		std::string bind = cvar.as<std::string>();
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);
		cfg->bindaddress = bind;

		server_.setup_listener(port, bind);
	}

	void setup_aliases(const x0::settings_value& cvar, const std::string& hostid)
	{
		auto aliases = cvar.as<std::vector<std::string>>();
		int port = x0::extract_port_from_hostid(hostid);
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);

		for (auto k = aliases.begin(), m = aliases.end(); k != m; ++k)
		{
			std::string hid(x0::make_hostid(*k, port));

			if (!register_vhost(hid, cfg))
			{
				char msg[1024];
				snprintf(msg, sizeof(msg), "Server alias '%s' already in use.", hid.c_str());
				throw std::runtime_error(msg);
			}

			server_.link_context(hostid, hid);

#if !defined(NDEBUG)
			debug(1, "Server alias '%s' (for bind '%s' on port %d) added.", hid.c_str(), cfg->bindaddress.c_str(), port);
#endif
		}
	}

	void setup_default(const x0::settings_value& cvar, const std::string& hostid)
	{
		bool is_default = cvar.as<bool>();
		int port = x0::extract_port_from_hostid(hostid);
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);

		if (is_default)
		{
			if (vhost_config *vhost = get_default_vhost(port))
			{
				char msg[256];

				std::snprintf(msg, sizeof(msg),
						"Cannot declare multiple virtual hosts as default "
						"with same port (%d). Conflicting hostnames: %s, %s.",
						port, vhost->name.c_str(), hostid.c_str());

				throw std::runtime_error(msg);
			}

			set_default_vhost(port, cfg);
		}
	}

	/** maps domain-name to given vhost config.
	 * \retval true success
	 * \retval false failed, there is already a vhost assigned to this name.
	 */
	bool register_vhost(const std::string& name, vhost_config *cfg)
	{
		//DEBUG("Registering vhost: %s [%s]\n", name.c_str(), cfg->name.c_str());
		if (mappings.find(name) == mappings.end())
		{
			mappings.insert({{name, cfg}});
			return true;
		}
		return false;
	}

	void set_default_vhost(int port, vhost_config *cfg)
	{
#if !defined(NDEBUG)
		debug(1, "set default host '%s'", cfg->name.c_str());
#endif
		default_hosts[port] = cfg;
	}

	vhost_config *get_default_vhost(int port)
	{
		auto i = default_hosts.find(port);

		if (i != default_hosts.end())
			return i->second;

		return NULL;
	}

	vhost_config *get_vhost(const std::string& name)
	{
		auto vh = mappings.find(name);
		if (vh != mappings.end())
			return vh->second;

		return NULL;
	}

	virtual void configure()
	{
		post_config();
	}

	void post_config()
	{
		// verify, that we have at least one vhost defined:
		// TODO

		// verify, that every listener has a default  vhost:
		for (auto i = server_.listeners().begin(), e = server_.listeners().end(); i != e; ++i)
		{
			if (!get_default_vhost((*i)->port()))
			{
				log(x0::severity::warn,
					"No default host defined for listener at port %d.",
					(*i)->port());
			}
		}
	} // }}}

private:
	void resolve_document_root(x0::request *in)
	{
		std::string hostid(in->hostid());

		vhost_config *vhost = get_vhost(hostid);
		if (!vhost)
		{
			vhost = get_default_vhost(in->connection.local_port());
			if (!vhost)
			{
#if !defined(NDEBUG)
				debug(1, "vhost_basic: no vhost config found for [%s]", hostid.c_str());
#endif
				return;
			}
			in->set_hostid(vhost->name);
		}

		in->document_root = vhost->document_root;

		//DEBUG("vhost_basic: resolved [%s] to document_root [%s]", hostid.c_str(), in->document_root.c_str());
	}
};

X0_EXPORT_PLUGIN(vhost_basic);
<commit_msg>drop debug prints<commit_after>/* <x0/mod_vhost_basic.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/plugin.hpp>
#include <x0/server.hpp>
#include <x0/request.hpp>
#include <x0/response.hpp>
#include <x0/listener.hpp>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

/**
 * \ingroup plugins
 * \brief provides a basic config-file based virtual hosting facility.
 *
 *

 * -- example configuration
 *
 * BindAddress = '0::0';             -- default bind address
 * Listen = 80;                      -- default listening port
 * DefaultHost = 'www.example.com';  -- default vhost to choose when we receive an unknown Host-request-header.
 *
 * Hosts = {
 *     ['www.example.com'] = {
 *         ServerAliases = { 'www.example.net', 'example.com', 'example.net' };
 *         DocumentRoot = '/var/www/example.com/htdocs';
 *     };
 *     ['localhost:8080'] = {
 *         DocumentRoot = '/var/www/example.com/htdocs';
 *         BindAddress = 'localhost';
 *
 *         Secure = true;
 *         CertFile = 'cert.pem';
 *         KeyFile = 'key.pem';
 *         TrustFile = 'ca.pem';
 *         CrlFile = 'crl.pem';
 *     };
 * };
 *

 */
class vhost_basic_plugin :
	public x0::plugin
{
private:
	struct vhost_config
	{
		std::string name;
		std::string document_root;
		std::string bindaddress;
	};

	x0::server::request_parse_hook::connection c;
	std::map<std::string, vhost_config *> mappings; // [hostname:port] -> vhost_config
	std::map<int, vhost_config *> default_hosts; // [port] -> vhost_config

public:
	vhost_basic_plugin(x0::server& srv, const std::string& name) :
		x0::plugin(srv, name)
	{
		using namespace std::placeholders;

		c = server_.resolve_document_root.connect(std::bind(&vhost_basic_plugin::resolve_document_root, this, _1));

		server_.register_cvar_host("DocumentRoot", std::bind(&vhost_basic_plugin::setup_docroot, this, _1, _2), 0);
		server_.register_cvar_host("Default", std::bind(&vhost_basic_plugin::setup_default, this, _1, _2), 1);
		server_.register_cvar_host("BindAddress", std::bind(&vhost_basic_plugin::setup_bindaddress, this, _1, _2), 1);
		server_.register_cvar_host("Aliases", std::bind(&vhost_basic_plugin::setup_aliases, this, _1, _2), 1);
	}

	~vhost_basic_plugin()
	{
		server_.resolve_document_root.disconnect(c);
	}

	void setup_docroot(const x0::settings_value& cvar, const std::string& hostid)
	{
		std::string document_root = cvar.as<std::string>();

		if (document_root.empty())
		{
			char msg[256];
			std::snprintf(msg, sizeof(msg),
				"vhost_basic[%s]: document root must not be empty.",
				hostid.c_str());

			throw std::runtime_error(msg);
		}

		if (document_root[0] != '/')
		{
			log(x0::severity::warn,
				"vhost_basic[%s]: document root should be an absolute path: '%s'",
				hostid.c_str(), document_root.c_str());
		}

		vhost_config *cfg = server_.create_context<vhost_config>(this, hostid);
		cfg->name = hostid;
		cfg->document_root = document_root;

		// register primary [hostname:port]
		if (!register_vhost(hostid, cfg))
		{
			char msg[1024];
			snprintf(msg, sizeof(msg), "Server name '%s' already in use.", hostid.c_str());
			throw std::runtime_error(msg);
		}
	}

	void setup_bindaddress(const x0::settings_value& cvar, const std::string& hostid)
	{
		int port = x0::extract_port_from_hostid(hostid);
		std::string bind = cvar.as<std::string>();
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);
		cfg->bindaddress = bind;

		server_.setup_listener(port, bind);
	}

	void setup_aliases(const x0::settings_value& cvar, const std::string& hostid)
	{
		auto aliases = cvar.as<std::vector<std::string>>();
		int port = x0::extract_port_from_hostid(hostid);
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);

		for (auto k = aliases.begin(), m = aliases.end(); k != m; ++k)
		{
			std::string hid(x0::make_hostid(*k, port));

			if (!register_vhost(hid, cfg))
			{
				char msg[1024];
				snprintf(msg, sizeof(msg), "Server alias '%s' already in use.", hid.c_str());
				throw std::runtime_error(msg);
			}

			server_.link_context(hostid, hid);

#if !defined(NDEBUG)
			debug(1, "Server alias '%s' (for bind '%s' on port %d) added.", hid.c_str(), cfg->bindaddress.c_str(), port);
#endif
		}
	}

	void setup_default(const x0::settings_value& cvar, const std::string& hostid)
	{
		bool is_default = cvar.as<bool>();
		int port = x0::extract_port_from_hostid(hostid);
		vhost_config *cfg = server_.context<vhost_config>(this, hostid);

		if (is_default)
		{
			if (vhost_config *vhost = get_default_vhost(port))
			{
				char msg[256];

				std::snprintf(msg, sizeof(msg),
						"Cannot declare multiple virtual hosts as default "
						"with same port (%d). Conflicting hostnames: %s, %s.",
						port, vhost->name.c_str(), hostid.c_str());

				throw std::runtime_error(msg);
			}

			set_default_vhost(port, cfg);
		}
	}

	/** maps domain-name to given vhost config.
	 * \retval true success
	 * \retval false failed, there is already a vhost assigned to this name.
	 */
	bool register_vhost(const std::string& name, vhost_config *cfg)
	{
		//debug(1, "Registering vhost: %s [%s]\n", name.c_str(), cfg->name.c_str());
		if (mappings.find(name) == mappings.end())
		{
			mappings.insert({{name, cfg}});
			return true;
		}
		return false;
	}

	void set_default_vhost(int port, vhost_config *cfg)
	{
#if !defined(NDEBUG)
		//debug(1, "set default host '%s'", cfg->name.c_str());
#endif
		default_hosts[port] = cfg;
	}

	vhost_config *get_default_vhost(int port)
	{
		auto i = default_hosts.find(port);

		if (i != default_hosts.end())
			return i->second;

		return NULL;
	}

	vhost_config *get_vhost(const std::string& name)
	{
		auto vh = mappings.find(name);
		if (vh != mappings.end())
			return vh->second;

		return NULL;
	}

	virtual void configure()
	{
		post_config();
	}

	void post_config()
	{
		// verify, that we have at least one vhost defined:
		// TODO

		// verify, that every listener has a default  vhost:
		for (auto i = server_.listeners().begin(), e = server_.listeners().end(); i != e; ++i)
		{
			if (!get_default_vhost((*i)->port()))
			{
				log(x0::severity::warn,
					"No default host defined for listener at port %d.",
					(*i)->port());
			}
		}
	} // }}}

private:
	void resolve_document_root(x0::request *in)
	{
		std::string hostid(in->hostid());

		vhost_config *vhost = get_vhost(hostid);
		if (!vhost)
		{
			vhost = get_default_vhost(in->connection.local_port());
			if (!vhost)
			{
#if !defined(NDEBUG)
				debug(1, "no vhost config found for [%s]", hostid.c_str());
#endif
				return;
			}
			in->set_hostid(vhost->name);
		}

		in->document_root = vhost->document_root;

		//debug(1, "resolved [%s] to document_root [%s]", hostid.c_str(), in->document_root.c_str());
	}
};

X0_EXPORT_PLUGIN(vhost_basic);
<|endoftext|>


<commit_before>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGAerodynamics.cpp
 Author:       Jon S. Berndt
 Date started: 09/13/00
 Purpose:      Encapsulates the aerodynamic forces (gear and collision)

 ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------
09/13/00   JSB   Created
04/22/01   JSB   Moved code into here from FGAircraft

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGAerodynamics.h"
#include "FGFactorGroup.h"
#include "FGCoefficient.h"
#include "FGPropertyManager.h"

static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.37 2002/05/16 13:07:16 jberndt Exp $";
static const char *IdHdr = ID_AERODYNAMICS;

const unsigned NAxes=6;
const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment",
                            "pitching-moment","yawing-moment" };

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
{
  Name = "FGAerodynamics";

  AxisIdx["DRAG"]  = 0;
  AxisIdx["SIDE"]  = 1;
  AxisIdx["LIFT"]  = 2;
  AxisIdx["ROLL"]  = 3;
  AxisIdx["PITCH"] = 4;
  AxisIdx["YAW"]   = 5;

  Coeff = new CoeffArray[6];

  impending_stall = stall_hyst = 0.0;
  alphaclmin = alphaclmax = 0.0;
  alphahystmin = alphahystmax = 0.0;
  clsq = lod = 0.0;
  alphaw = 0.0;
  bind();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGAerodynamics::~FGAerodynamics()
{
  unsigned int i,j;

  unbind();

  for (i=0; i<6; i++) {
    for (j=0; j<Coeff[i].size(); j++) {
      delete Coeff[i][j];
    }
  }
  delete[] Coeff;

  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAerodynamics::Run(void)
{
  unsigned int axis_ctr,ctr;
  double alpha, twovel;

  if (!FGModel::Run()) {

    twovel = 2*Translation->GetVt();
    if (twovel > 0) {
      bi2vel = Aircraft->GetWingSpan() / twovel;
      ci2vel = Aircraft->Getcbar() / twovel;
    }

    alphaw = Translation->Getalpha() + Aircraft->GetWingIncidence();

    alpha = Translation->Getalpha();

    if (alphaclmax != 0) {
      if (alpha > 0.85*alphaclmax) {
        impending_stall = 10*(alpha/alphaclmax - 0.85);
      } else {
        impending_stall = 0;
      }
    }

    if (alphahystmax != 0.0 && alphahystmin != 0.0) {
      if (alpha > alphahystmax) {
         stall_hyst = 1;
      } else if (alpha < alphahystmin) {
         stall_hyst = 0;
      }
    }

    vLastFs = vFs;
    vFs.InitMatrix();

    for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
      for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
        vFs(axis_ctr+1) += Coeff[axis_ctr][ctr]->TotalValue();
      }
    }

    //correct signs of drag and lift to wind axes convention
    //positive forward, right, down
    if ( Translation->Getqbar() > 0) {
      clsq = vFs(eLift) / (Aircraft->GetWingArea()*Translation->Getqbar());
      clsq *= clsq;
    }
    if ( vFs(eDrag)  > 0) {
      lod = vFs(eLift) / vFs(eDrag);
    }

    //correct signs of drag and lift to wind axes convention
    //positive forward, right, down
    vFs(eDrag)*=-1; vFs(eLift)*=-1;

    vForces = State->GetTs2b()*vFs;

    vDXYZcg(eX) = -(Aircraft->GetXYZrp(eX)
                      - MassBalance->GetXYZcg(eX))*inchtoft;
    vDXYZcg(eY) =  (Aircraft->GetXYZrp(eY)
                      - MassBalance->GetXYZcg(eY))*inchtoft;
    vDXYZcg(eZ) = -(Aircraft->GetXYZrp(eZ)
                      - MassBalance->GetXYZcg(eZ))*inchtoft;

    vMoments = vDXYZcg*vForces; // M = r X F

    for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
      for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
        vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->TotalValue();
      }
    }

    return false;
  } else {
    return true;
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAerodynamics::Load(FGConfigFile* AC_cfg)
{
  string parameter, axis, scratch;

  AC_cfg->GetNextConfigLine();

  while ((parameter = AC_cfg->GetValue()) != string("/AERODYNAMICS")) {
    if (parameter == "AXIS") {
      CoeffArray ca;
      axis = AC_cfg->GetValue("NAME");
      AC_cfg->GetNextConfigLine();
      while ((parameter = AC_cfg->GetValue()) != string("/AXIS")) {
        if ( parameter == "COEFFICIENT" ) {
          ca.push_back( new FGCoefficient(FDMExec) );
          ca.back()->Load(AC_cfg);
        } else if ( parameter == "GROUP" ) {
          ca.push_back( new FGFactorGroup(FDMExec) );
          ca.back()->Load(AC_cfg);
        }
      }
      Coeff[AxisIdx[axis]] = ca;
      AC_cfg->GetNextConfigLine();
    } else if (parameter == "AC_ALPHALIMITS") {
      *AC_cfg >> scratch >> alphaclmin >> alphaclmax;
      if (debug_lvl > 0) cout << "    Maximum Alpha: " << alphaclmax
                              << "    Minimum Alpha: " << alphaclmin
                              << endl;
    } else if (parameter == "AC_HYSTLIMITS") {
      *AC_cfg >> scratch >> alphahystmin >> alphahystmax;
      if (debug_lvl > 0) cout << "    Hysteresis Start: " << alphahystmax
                              << "    Hysteresis End: " << alphahystmin
                              << endl;
    }
  }

  bindModel();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGAerodynamics::GetCoefficientStrings(void)
{
  string CoeffStrings = "";
  bool firstime = true;
  unsigned int axis, sd;

  for (axis = 0; axis < 6; axis++) {
    for (sd = 0; sd < Coeff[axis].size(); sd++) {
      if (firstime) {
        firstime = false;
      } else {
        CoeffStrings += ", ";
      }
      CoeffStrings += Coeff[axis][sd]->GetCoefficientStrings();
    }
  }
  return CoeffStrings;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGAerodynamics::GetCoefficientValues(void)
{
  string SDValues = "";
  bool firstime = true;

  for (unsigned int axis = 0; axis < 6; axis++) {
    for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
      if (firstime) {
        firstime = false;
      } else {
        SDValues += ", ";
      }
      SDValues += Coeff[axis][sd]->GetCoefficientValues();
    }
  }

  return SDValues;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::bind(void)
{
  typedef double (FGAerodynamics::*PMF)(int) const;

  PropertyManager->Tie("forces/fbx-aero-lbs", this,1,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("forces/fby-aero-lbs", this,2,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("forces/fbz-aero-lbs", this,3,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("moments/l-aero-lbsft", this,1,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("moments/m-aero-lbsft", this,2,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("moments/n-aero-lbsft", this,3,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("forces/fwx-aero-lbs", this,1,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/fwy-aero-lbs", this,2,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/fwz-aero-lbs", this,3,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/lod-norm", this,
                       &FGAerodynamics::GetLoD);
  PropertyManager->Tie("aero/cl-squared-norm", this,
                       &FGAerodynamics::GetClSquared);
  PropertyManager->Tie("aero/alpha-max-deg", this,
                       &FGAerodynamics::GetAlphaCLMax,
                       &FGAerodynamics::SetAlphaCLMax,
                       true);
  PropertyManager->Tie("aero/alpha-min-deg", this,
                       &FGAerodynamics::GetAlphaCLMin,
                       &FGAerodynamics::SetAlphaCLMin,
                       true);
  PropertyManager->Tie("aero/bi2vel", this,
                       &FGAerodynamics::GetBI2Vel);
  PropertyManager->Tie("aero/ci2vel", this,
                       &FGAerodynamics::GetCI2Vel);
  PropertyManager->Tie("aero/alpha-wing-rad", this,
                       &FGAerodynamics::GetAlphaW);
  PropertyManager->Tie("systems/stall-warn-norm", this,
                        &FGAerodynamics::GetStallWarn);
  PropertyManager->Tie("aero/stall-hyst-norm", this,
                        &FGAerodynamics::GetHysteresisParm);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::bindModel(void)
{
  unsigned i,j;
  FGPropertyManager* node;
  string axis_node_name;
  node = PropertyManager->GetNode("aero/buildup",true);
  for (i=0;i<NAxes;i++) {
     node = node->GetNode( string(AxisNames[i]),true );
     for (j=0; j < Coeff[i].size(); j++) {
       Coeff[i][j]->bind(node);
     }
     node = (FGPropertyManager*)node->getParent();
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::unbind(void)
{
  unsigned i,j;

  PropertyManager->Untie("forces/fbx-aero-lbs");
  PropertyManager->Untie("forces/fby-aero-lbs");
  PropertyManager->Untie("forces/fbz-aero-lbs");
  PropertyManager->Untie("moments/l-aero-lbsft");
  PropertyManager->Untie("moments/m-aero-lbsft");
  PropertyManager->Untie("moments/n-aero-lbsft");
  PropertyManager->Untie("forces/fwx-aero-lbs");
  PropertyManager->Untie("forces/fwy-aero-lbs");
  PropertyManager->Untie("forces/fwz-aero-lbs");
  PropertyManager->Untie("forces/lod-norm");
  PropertyManager->Untie("aero/cl-squared-norm");
  PropertyManager->Untie("metrics/alpha-max-deg");
  PropertyManager->Untie("metrics/alpha-min-deg");
  PropertyManager->Untie("aero/bi2vel");
  PropertyManager->Untie("aero/ci2vel");
  PropertyManager->Untie("aero/alpha-wing-rad");
  PropertyManager->Untie("systems/stall-warn-norm");

  for ( i=0; i<NAxes; i++ ) {
     for ( j=0; j < Coeff[i].size(); j++ ) {
       Coeff[i][j]->unbind();

     }
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGAerodynamics::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor

    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGAerodynamics" << endl;
    if (from == 1) cout << "Destroyed:    FGAerodynamics" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}

<commit_msg>Fixed my failure to change property tree path for two alpha vars when moved to FGAerodynamics<commit_after>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGAerodynamics.cpp
 Author:       Jon S. Berndt
 Date started: 09/13/00
 Purpose:      Encapsulates the aerodynamic forces (gear and collision)

 ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------
09/13/00   JSB   Created
04/22/01   JSB   Moved code into here from FGAircraft

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGAerodynamics.h"
#include "FGFactorGroup.h"
#include "FGCoefficient.h"
#include "FGPropertyManager.h"

static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.38 2002/05/26 15:25:27 jberndt Exp $";
static const char *IdHdr = ID_AERODYNAMICS;

const unsigned NAxes=6;
const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment",
                            "pitching-moment","yawing-moment" };

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
{
  Name = "FGAerodynamics";

  AxisIdx["DRAG"]  = 0;
  AxisIdx["SIDE"]  = 1;
  AxisIdx["LIFT"]  = 2;
  AxisIdx["ROLL"]  = 3;
  AxisIdx["PITCH"] = 4;
  AxisIdx["YAW"]   = 5;

  Coeff = new CoeffArray[6];

  impending_stall = stall_hyst = 0.0;
  alphaclmin = alphaclmax = 0.0;
  alphahystmin = alphahystmax = 0.0;
  clsq = lod = 0.0;
  alphaw = 0.0;
  bind();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGAerodynamics::~FGAerodynamics()
{
  unsigned int i,j;

  unbind();

  for (i=0; i<6; i++) {
    for (j=0; j<Coeff[i].size(); j++) {
      delete Coeff[i][j];
    }
  }
  delete[] Coeff;

  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAerodynamics::Run(void)
{
  unsigned int axis_ctr,ctr;
  double alpha, twovel;

  if (!FGModel::Run()) {

    twovel = 2*Translation->GetVt();
    if (twovel > 0) {
      bi2vel = Aircraft->GetWingSpan() / twovel;
      ci2vel = Aircraft->Getcbar() / twovel;
    }

    alphaw = Translation->Getalpha() + Aircraft->GetWingIncidence();

    alpha = Translation->Getalpha();

    if (alphaclmax != 0) {
      if (alpha > 0.85*alphaclmax) {
        impending_stall = 10*(alpha/alphaclmax - 0.85);
      } else {
        impending_stall = 0;
      }
    }

    if (alphahystmax != 0.0 && alphahystmin != 0.0) {
      if (alpha > alphahystmax) {
         stall_hyst = 1;
      } else if (alpha < alphahystmin) {
         stall_hyst = 0;
      }
    }

    vLastFs = vFs;
    vFs.InitMatrix();

    for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
      for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
        vFs(axis_ctr+1) += Coeff[axis_ctr][ctr]->TotalValue();
      }
    }

    //correct signs of drag and lift to wind axes convention
    //positive forward, right, down
    if ( Translation->Getqbar() > 0) {
      clsq = vFs(eLift) / (Aircraft->GetWingArea()*Translation->Getqbar());
      clsq *= clsq;
    }
    if ( vFs(eDrag)  > 0) {
      lod = vFs(eLift) / vFs(eDrag);
    }

    //correct signs of drag and lift to wind axes convention
    //positive forward, right, down
    vFs(eDrag)*=-1; vFs(eLift)*=-1;

    vForces = State->GetTs2b()*vFs;

    vDXYZcg(eX) = -(Aircraft->GetXYZrp(eX)
                      - MassBalance->GetXYZcg(eX))*inchtoft;
    vDXYZcg(eY) =  (Aircraft->GetXYZrp(eY)
                      - MassBalance->GetXYZcg(eY))*inchtoft;
    vDXYZcg(eZ) = -(Aircraft->GetXYZrp(eZ)
                      - MassBalance->GetXYZcg(eZ))*inchtoft;

    vMoments = vDXYZcg*vForces; // M = r X F

    for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
      for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
        vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->TotalValue();
      }
    }

    return false;
  } else {
    return true;
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGAerodynamics::Load(FGConfigFile* AC_cfg)
{
  string parameter, axis, scratch;

  AC_cfg->GetNextConfigLine();

  while ((parameter = AC_cfg->GetValue()) != string("/AERODYNAMICS")) {
    if (parameter == "AXIS") {
      CoeffArray ca;
      axis = AC_cfg->GetValue("NAME");
      AC_cfg->GetNextConfigLine();
      while ((parameter = AC_cfg->GetValue()) != string("/AXIS")) {
        if ( parameter == "COEFFICIENT" ) {
          ca.push_back( new FGCoefficient(FDMExec) );
          ca.back()->Load(AC_cfg);
        } else if ( parameter == "GROUP" ) {
          ca.push_back( new FGFactorGroup(FDMExec) );
          ca.back()->Load(AC_cfg);
        }
      }
      Coeff[AxisIdx[axis]] = ca;
      AC_cfg->GetNextConfigLine();
    } else if (parameter == "AC_ALPHALIMITS") {
      *AC_cfg >> scratch >> alphaclmin >> alphaclmax;
      if (debug_lvl > 0) cout << "    Maximum Alpha: " << alphaclmax
                              << "    Minimum Alpha: " << alphaclmin
                              << endl;
    } else if (parameter == "AC_HYSTLIMITS") {
      *AC_cfg >> scratch >> alphahystmin >> alphahystmax;
      if (debug_lvl > 0) cout << "    Hysteresis Start: " << alphahystmax
                              << "    Hysteresis End: " << alphahystmin
                              << endl;
    }
  }

  bindModel();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGAerodynamics::GetCoefficientStrings(void)
{
  string CoeffStrings = "";
  bool firstime = true;
  unsigned int axis, sd;

  for (axis = 0; axis < 6; axis++) {
    for (sd = 0; sd < Coeff[axis].size(); sd++) {
      if (firstime) {
        firstime = false;
      } else {
        CoeffStrings += ", ";
      }
      CoeffStrings += Coeff[axis][sd]->GetCoefficientStrings();
    }
  }
  return CoeffStrings;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

string FGAerodynamics::GetCoefficientValues(void)
{
  string SDValues = "";
  bool firstime = true;

  for (unsigned int axis = 0; axis < 6; axis++) {
    for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
      if (firstime) {
        firstime = false;
      } else {
        SDValues += ", ";
      }
      SDValues += Coeff[axis][sd]->GetCoefficientValues();
    }
  }

  return SDValues;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::bind(void)
{
  typedef double (FGAerodynamics::*PMF)(int) const;

  PropertyManager->Tie("forces/fbx-aero-lbs", this,1,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("forces/fby-aero-lbs", this,2,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("forces/fbz-aero-lbs", this,3,
                       (PMF)&FGAerodynamics::GetForces);
  PropertyManager->Tie("moments/l-aero-lbsft", this,1,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("moments/m-aero-lbsft", this,2,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("moments/n-aero-lbsft", this,3,
                       (PMF)&FGAerodynamics::GetMoments);
  PropertyManager->Tie("forces/fwx-aero-lbs", this,1,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/fwy-aero-lbs", this,2,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/fwz-aero-lbs", this,3,
                       (PMF)&FGAerodynamics::GetvFs);
  PropertyManager->Tie("forces/lod-norm", this,
                       &FGAerodynamics::GetLoD);
  PropertyManager->Tie("aero/cl-squared-norm", this,
                       &FGAerodynamics::GetClSquared);
  PropertyManager->Tie("aero/alpha-max-deg", this,
                       &FGAerodynamics::GetAlphaCLMax,
                       &FGAerodynamics::SetAlphaCLMax,
                       true);
  PropertyManager->Tie("aero/alpha-min-deg", this,
                       &FGAerodynamics::GetAlphaCLMin,
                       &FGAerodynamics::SetAlphaCLMin,
                       true);
  PropertyManager->Tie("aero/bi2vel", this,
                       &FGAerodynamics::GetBI2Vel);
  PropertyManager->Tie("aero/ci2vel", this,
                       &FGAerodynamics::GetCI2Vel);
  PropertyManager->Tie("aero/alpha-wing-rad", this,
                       &FGAerodynamics::GetAlphaW);
  PropertyManager->Tie("systems/stall-warn-norm", this,
                        &FGAerodynamics::GetStallWarn);
  PropertyManager->Tie("aero/stall-hyst-norm", this,
                        &FGAerodynamics::GetHysteresisParm);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::bindModel(void)
{
  unsigned i,j;
  FGPropertyManager* node;
  string axis_node_name;
  node = PropertyManager->GetNode("aero/buildup",true);
  for (i=0;i<NAxes;i++) {
     node = node->GetNode( string(AxisNames[i]),true );
     for (j=0; j < Coeff[i].size(); j++) {
       Coeff[i][j]->bind(node);
     }
     node = (FGPropertyManager*)node->getParent();
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGAerodynamics::unbind(void)
{
  unsigned i,j;

  PropertyManager->Untie("forces/fbx-aero-lbs");
  PropertyManager->Untie("forces/fby-aero-lbs");
  PropertyManager->Untie("forces/fbz-aero-lbs");
  PropertyManager->Untie("moments/l-aero-lbsft");
  PropertyManager->Untie("moments/m-aero-lbsft");
  PropertyManager->Untie("moments/n-aero-lbsft");
  PropertyManager->Untie("forces/fwx-aero-lbs");
  PropertyManager->Untie("forces/fwy-aero-lbs");
  PropertyManager->Untie("forces/fwz-aero-lbs");
  PropertyManager->Untie("forces/lod-norm");
  PropertyManager->Untie("aero/cl-squared-norm");
  PropertyManager->Untie("aero/alpha-max-deg");
  PropertyManager->Untie("aero/alpha-min-deg");
  PropertyManager->Untie("aero/bi2vel");
  PropertyManager->Untie("aero/ci2vel");
  PropertyManager->Untie("aero/alpha-wing-rad");
  PropertyManager->Untie("systems/stall-warn-norm");

  for ( i=0; i<NAxes; i++ ) {
     for ( j=0; j < Coeff[i].size(); j++ ) {
       Coeff[i][j]->unbind();

     }
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGAerodynamics::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor

    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGAerodynamics" << endl;
    if (from == 1) cout << "Destroyed:    FGAerodynamics" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}

<|endoftext|>


<commit_before>// see [A multi-threaded Producer Consumer with C++11](http://codereview.stackexchange.com/questions/84109/a-multi-threaded-producer-consumer-with-c11)
// note that `lock_guard` is recommended instead of `unique_lock` as it releases lock automatically follow RAII leaving the lock scope.
// see also [](http://www.boost.org/doc/libs/1_54_0/doc/html/lockfree/examples.html) for atomics instead of locks.
//

#include <iostream>
#include <thread>
#include <vector> // for creating an equivalent to `boost::thread_group`
#include <mutex>
#include <condition_variable>
#include <deque>
#include <random>

template<class T>
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os)
{
  t.print(os);
  return os;
}

// to store robot commands
template <typename T>
class Buffer
{
public:
    void add(T&& item)
    {
      std::unique_lock<std::mutex> locker(mu_);
      cond_.wait(locker, [this] { return buffer_.size() < size_; } );
      std::cout << "add(): pushed " << item << "\n";
      buffer_.push_back(item);
      cond_.notify_all();
      return;
    }

    T remove()
    {
      std::unique_lock<std::mutex> locker(mu_);
      cond_.wait(locker, [this] { return !buffer_.empty(); } );
      auto back = buffer_.back();
      buffer_.pop_back();
      std::cout << "remove(): popped " << back << "\n";
      cond_.notify_all();
      return back;
    }

    bool empty() const
    {
      return buffer_.empty();
    }

    Buffer() {}

private:
    std::mutex mu_;
    std::condition_variable cond_;

    std::deque<T> buffer_;
    const unsigned size_ = 128;
};

struct RobotCommand
{
  int task_id, sequence_id, command_type;

  void print(std::ostream& strm) const
  {
    strm << "task_id: " << task_id
         << " sequence_id: " << sequence_id
         << " command_type: " << command_type;
  }
};

void join_all(std::vector<std::thread>& grp) {
    for (auto& thr : grp)
        if (thr.joinable())
            thr.join();
}

main()
{
    // Non-deterministic pseudo-random numbers generator
    thread_local std::random_device rd;
    // Pseudo-random engine
    thread_local std::mt19937 engine(rd());
    // Linear distribution in [0, 100[
    thread_local std::uniform_int_distribution<int> dist(0, 99);

    std::vector<std::thread> producer_grp, consumer_grp;

    const int producer_thread_count = 12;
    const int consumer_thread_count = 12;
    Buffer<int> buffer;
    for (int i = 0; i < producer_thread_count; i++) {
        int num = dist(engine);
        producer_grp.emplace_back(&Buffer<int>::add, &buffer, num);
    }
    for (int i = 0; i < consumer_thread_count; i++) {
        consumer_grp.emplace_back(&Buffer<int>::remove, &buffer);
    }

    join_all(producer_grp);
    join_all(consumer_grp);
}

<commit_msg>fix move semantics.<commit_after>// see [A multi-threaded Producer Consumer with C++11](http://codereview.stackexchange.com/questions/84109/a-multi-threaded-producer-consumer-with-c11)
// note that `lock_guard` is recommended instead of `unique_lock` as it releases lock automatically follow RAII leaving the lock scope.
// see also [](http://www.boost.org/doc/libs/1_54_0/doc/html/lockfree/examples.html) for atomics instead of locks.
//

#include <iostream>
#include <thread>
#include <vector> // for creating an equivalent to `boost::thread_group`
#include <mutex>
#include <condition_variable>
#include <deque>
#include <random>

template<class T>
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os)
{
  t.print(os);
  return os;
}

// to store robot commands
template <typename T>
class Buffer
{
public:
    void add(T&& item)
    {
      std::unique_lock<std::mutex> locker(mu_);
      cond_.wait(locker, [this] { return buffer_.size() < size_; } );
      std::cout << "add(): pushed " << item << "\n";
      buffer_.emplace_back(std::move(item));
      cond_.notify_all();
    }

    T remove()
    {
      std::unique_lock<std::mutex> locker(mu_);
      cond_.wait(locker, [this] { return !buffer_.empty(); } );
      auto back = std::move(buffer_.back());
      buffer_.pop_back();
      std::cout << "remove(): popped " << back << "\n";
      cond_.notify_all();
      return back;
    }

    bool empty() const
    {
      return buffer_.empty();
    }

    Buffer() {}

private:
    std::mutex mu_;
    std::condition_variable cond_;

    std::deque<T> buffer_;
    const unsigned size_ = 128;
};

struct RobotCommand
{
  int task_id, sequence_id, command_type;

  void print(std::ostream& strm) const
  {
    strm << "task_id: " << task_id
         << " sequence_id: " << sequence_id
         << " command_type: " << command_type;
  }
};

void join_all(std::vector<std::thread>& grp) {
    for (auto& thr : grp)
        if (thr.joinable())
            thr.join();
}

main()
{
    // Non-deterministic pseudo-random numbers generator
    thread_local std::random_device rd;
    // Pseudo-random engine
    thread_local std::mt19937 engine(rd());
    // Linear distribution in [0, 100[
    thread_local std::uniform_int_distribution<int> dist(0, 99);

    std::vector<std::thread> producer_grp, consumer_grp;

    const int producer_thread_count = 12;
    const int consumer_thread_count = 12;
    Buffer<int> buffer;
    for (int i = 0; i < producer_thread_count; i++) {
        int num = dist(engine);
        producer_grp.emplace_back(&Buffer<int>::add, &buffer, num);
    }
    for (int i = 0; i < consumer_thread_count; i++) {
        consumer_grp.emplace_back(&Buffer<int>::remove, &buffer);
    }

    join_all(producer_grp);
    join_all(consumer_grp);
}

<|endoftext|>