<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/gl/kernels/conv.h"

#include <memory>
#include <vector>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/convert.h"
#include "tensorflow/lite/delegates/gpu/common/operations.h"
#include "tensorflow/lite/delegates/gpu/common/shape.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"
#include "tensorflow/lite/delegates/gpu/common/types.h"
#include "tensorflow/lite/delegates/gpu/common/util.h"
#include "tensorflow/lite/delegates/gpu/gl/node_shader.h"
#include "tensorflow/lite/delegates/gpu/gl/variable.h"
#include "tensorflow/lite/delegates/gpu/gl/workgroups/ideal_workgroup_picker.h"

namespace tflite {
namespace gpu {
namespace gl {
namespace {

class Convolution : public NodeShader {
 public:
  absl::Status GenerateCode(const GenerationContext& ctx,
                            GeneratedCode* generated_code) const final {
    if (ctx.input_shapes.size() != 1) {
      return absl::UnimplementedError(
          "Convolution does not support more than 1 runtime tensor");
    }
    const auto& attr =
        absl::any_cast<const Convolution2DAttributes&>(ctx.op_attr);
    auto weights = attr.weights.shape;
    const int offsets_count = weights.h * weights.w;
    const bool offsets_count_too_large = offsets_count > kMaxConstArraySize;
    std::vector<Variable> parameters;
    if (offsets_count_too_large) {
      parameters = {
          {"input_data_0_h", static_cast<int>(ctx.input_shapes[0][1])},
          {"input_data_0_w", static_cast<int>(ctx.input_shapes[0][2])},
          {"padding_w", attr.padding.prepended.w},
          {"padding_h", attr.padding.prepended.h},
          {"dilation_w", attr.dilations.w},
          {"dilation_h", attr.dilations.h},
          {"kernel_w", weights.w},
          {"kernel_h", weights.h},
          {"src_depth", DivideRoundUp(weights.i, 4)},
          {"stride", int2(attr.strides.w, attr.strides.h)},
      };
    } else {
      std::vector<int2> offsets;
      for (int h = 0; h < weights.h; ++h) {
        for (int w = 0; w < weights.w; ++w) {
          offsets.emplace_back(w * attr.dilations.w - attr.padding.prepended.w,
                               h * attr.dilations.h - attr.padding.prepended.h);
        }
      }
      parameters = {
          {"input_data_0_h", static_cast<int>(ctx.input_shapes[0][1])},
          {"input_data_0_w", static_cast<int>(ctx.input_shapes[0][2])},
          {"offsets_count", offsets_count},
          {"offsets", offsets},
          {"src_depth", DivideRoundUp(weights.i, 4)},
          {"stride", int2(attr.strides.w, attr.strides.h)},
      };
    }

    // at least one padding is not empty
    bool non_empty_padding =
        attr.padding.appended.h != 0 || attr.padding.appended.w != 0 ||
        attr.padding.prepended.h != 0 || attr.padding.prepended.w != 0;

    std::vector<std::pair<std::string, Object>> objects = {
        {"weights", MakeReadonlyObject(Get3DSizeForPHWO4I4(attr.weights.shape),
                                       ConvertToPHWO4I4(attr.weights))}};

    std::string source;
    if (offsets_count_too_large) {
      source = R"(
      int i = 0;
      for (int ky = 0; ky < $kernel_h$; ky++) {
        for (int kx = 0; kx < $kernel_w$; kx++, i++) {
          ivec2 coord = gid.xy * $stride$ + ivec2(kx * $dilation_w$ - $padding_w$, ky * $dilation_h$ - $padding_h$);)";
    } else {
      source = R"(
        for (int i = 0; i < $offsets_count$; ++i) {
          ivec2 coord = gid.xy * $stride$ + $offsets[i]$;)";
    }
    if (non_empty_padding) {
      source += R"(
        if (coord.x < 0 || coord.y < 0 || coord.x >= $input_data_0_w$ || coord.y >= $input_data_0_h$) {
          continue;
        })";
    }
    source += R"(
          for (int l = 0; l < $src_depth$; ++l) {
            vec4 input_ = $input_data_0[coord.x, coord.y, l]$;
            value_0.x += dot(input_, $weights[l * 4 + 0, i, gid.z]$);
            value_0.y += dot(input_, $weights[l * 4 + 1, i, gid.z]$);
            value_0.z += dot(input_, $weights[l * 4 + 2, i, gid.z]$);
            value_0.w += dot(input_, $weights[l * 4 + 3, i, gid.z]$);
          }
        }
)";
    if (offsets_count_too_large) {
      source += R"(
      }
)";
    }
    if (!attr.bias.data.empty()) {
      source += "value_0 += $bias[gid.z]$;\n";
      objects.push_back({"bias", MakeReadonlyObject(attr.bias.data)});
    }

    *generated_code = {
        /*parameters=*/std::move(parameters),
        /*objects=*/std::move(objects),
        /*shared_variables=*/{},
        /*workload=*/uint3(),
        /*workgroup=*/
        GetIdealWorkgroupIfPossible(
            *ctx.gpu_info, OperationType::CONVOLUTION_2D,
            HW(weights.h, weights.w), attr.strides, uint3(0, 0, 0),
            OHWI(weights.o, ctx.input_shapes[0][1], ctx.input_shapes[0][2],
                 ctx.input_shapes[0][3])),
        /*source_code=*/std::move(source),
        /*input=*/IOStructure::ONLY_DEFINITIONS,
        /*output=*/IOStructure::AUTO,
    };
    return absl::OkStatus();
  }
};

int SelectMultiplier(int32_t input_width,
                     const NodeShader::GenerationContext& ctx) {
  std::vector<int> multipliers = {4, 2};
  if (ctx.gpu_info->IsAMD()) {
    return 1;
  }
  if (!ctx.compiler_options.allow_precision_loss && ctx.gpu_info->IsMali()) {
    multipliers = {2};
  }
  for (int i : multipliers) {
    if (input_width % i == 0) {
      return i;
    }
  }
  return 1;
}

class Convolution1x1 : public NodeShader {
 public:
  absl::Status GenerateCode(const GenerationContext& ctx,
                            GeneratedCode* generated_code) const final {
    if (ctx.input_shapes.size() != 1) {
      return absl::UnimplementedError(
          "Convolution does not support more than 1 runtime tensor");
    }
    const auto& attr =
        absl::any_cast<const Convolution2DAttributes&>(ctx.op_attr);
    if (attr.weights.shape.h != 1 || attr.weights.shape.w != 1) {
      return absl::UnimplementedError("Height and width should be 1.");
    }
    if (attr.dilations.h != 1 || attr.dilations.w != 1) {
      return absl::UnimplementedError("Dilations are not supported.");
    }
    if (attr.strides.h != 1 || attr.strides.w != 1) {
      return absl::UnimplementedError("Strides are not supported.");
    }
    if (attr.padding.appended.h != 0 || attr.padding.appended.w != 0 ||
        attr.padding.prepended.h != 0 || attr.padding.prepended.w != 0) {
      return absl::UnimplementedError("Padding is not supported.");
    }

    int multiplier = SelectMultiplier(ctx.input_shapes[0][2], ctx);

    std::vector<Variable> parameters = {
        {"src_depth",
         DivideRoundUp(static_cast<int>(ctx.input_shapes[0][3]), 4)},
    };

    std::vector<std::pair<std::string, Object>> objects = {
        {"weights",
         MakeReadonlyObject(uint3(4, DivideRoundUp(attr.weights.shape.i, 4),
                                  DivideRoundUp(attr.weights.shape.o, 4)),
                            ConvertToPHWO4I4(attr.weights))}};
    std::string source;
    for (int i = 0; i < multiplier; i++) {
      absl::StrAppend(&source, "highp vec4 result", i, " = vec4(0);\n");
    }
    absl::StrAppend(&source, "vec4 f;\n");
    absl::StrAppend(&source, "for (int l = 0; l < $src_depth$; ++l) {\n");
    for (int i = 0; i < multiplier; i++) {
      absl::StrAppend(&source, "  vec4 input", i, " = $input_data_0[gid.x * ",
                      multiplier, " + ", i, ",gid.y,l]$;\n");
    }
    for (int k = 0; k < 4; k++) {
      absl::StrAppend(&source, "  f = $weights[", k, ", l, gid.z]$;\n");
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "  result", i, "[", k, "] += dot(input", i,
                        ", f);\n");
      }
    }
    absl::StrAppend(&source, "}\n");
    if (!attr.bias.data.empty()) {
      objects.push_back({"bias", MakeReadonlyObject(attr.bias.data)});
      absl::StrAppend(&source, "vec4 b = $bias[gid.z]$;\n");
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "result", i, " += b;\n");
      }
    }
    if (multiplier != 1) {
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "$inplace_update:result", i, "$\n");
        absl::StrAppend(&source, "$output_data_0[gid.x * ", multiplier, " + ",
                        i, ",gid.y,gid.z] = result", i, "$;\n");
      }
    } else {
      absl::StrAppend(&source, "value_0 = result0;\n");
    }

    auto dst_depth = DivideRoundUp(ctx.output_shapes[0][3], 4);
    uint3 workgroup = uint3(16, 16, 1);
    if (ctx.gpu_info->IsAdreno()) {
      if (dst_depth >= 2) {
        workgroup = uint3(8, 8, 2);
      }
      if (dst_depth >= 4) {
        workgroup = uint3(4, 8, 4);
      }
      if (dst_depth >= 8) {
        workgroup = uint3(4, 4, 8);
      }
      if (dst_depth >= 32) {
        workgroup = uint3(4, 4, 16);
      }
      if (dst_depth >= 64) {
        workgroup = uint3(2, 8, 16);
      }
    } else {
      if (dst_depth >= 2) {
        workgroup = uint3(16, 8, 2);
      }
      if (dst_depth >= 4) {
        workgroup = uint3(16, 4, 4);
      }
      if (dst_depth >= 8) {
        workgroup = uint3(8, 4, 8);
      }
      if (dst_depth >= 32) {
        workgroup = uint3(8, 4, 8);
      }
      if (dst_depth >= 64) {
        workgroup = uint3(8, 4, 8);
      }
    }
    *generated_code = {
        /*parameters=*/std::move(parameters),
        /*objects=*/std::move(objects),
        /*shared_variables=*/{},
        /*workload=*/
        uint3(ctx.output_shapes[0][2] / multiplier, ctx.output_shapes[0][1],
              DivideRoundUp(ctx.output_shapes[0][3], 4)),
        /*workgroup=*/
        GetIdealWorkgroupIfPossible(
            *ctx.gpu_info, OperationType::CONVOLUTION_2D,
            HW(attr.weights.shape.h, attr.weights.shape.w), attr.strides,
            workgroup,
            OHWI(attr.weights.shape.o, ctx.input_shapes[0][1],
                 ctx.input_shapes[0][2], ctx.input_shapes[0][3])),
        /*source_code=*/std::move(source),
        /*input=*/IOStructure::ONLY_DEFINITIONS,
        /*output=*/multiplier == 1 ? IOStructure::AUTO
                                   : IOStructure::ONLY_DEFINITIONS,
    };
    return absl::OkStatus();
  }
};

}  // namespace

std::unique_ptr<NodeShader> NewConvolutionNodeShader() {
  return absl::make_unique<Convolution>();
}

std::unique_ptr<NodeShader> NewConvolution1x1NodeShader() {
  return absl::make_unique<Convolution1x1>();
}

}  // namespace gl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Force casting uploaded values to 32-bit float type for convolution 1x1.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/gl/kernels/conv.h"

#include <memory>
#include <vector>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/convert.h"
#include "tensorflow/lite/delegates/gpu/common/operations.h"
#include "tensorflow/lite/delegates/gpu/common/shape.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"
#include "tensorflow/lite/delegates/gpu/common/types.h"
#include "tensorflow/lite/delegates/gpu/common/util.h"
#include "tensorflow/lite/delegates/gpu/gl/node_shader.h"
#include "tensorflow/lite/delegates/gpu/gl/variable.h"
#include "tensorflow/lite/delegates/gpu/gl/workgroups/ideal_workgroup_picker.h"

namespace tflite {
namespace gpu {
namespace gl {
namespace {

class Convolution : public NodeShader {
 public:
  absl::Status GenerateCode(const GenerationContext& ctx,
                            GeneratedCode* generated_code) const final {
    if (ctx.input_shapes.size() != 1) {
      return absl::UnimplementedError(
          "Convolution does not support more than 1 runtime tensor");
    }
    const auto& attr =
        absl::any_cast<const Convolution2DAttributes&>(ctx.op_attr);
    auto weights = attr.weights.shape;
    const int offsets_count = weights.h * weights.w;
    const bool offsets_count_too_large = offsets_count > kMaxConstArraySize;
    std::vector<Variable> parameters;
    if (offsets_count_too_large) {
      parameters = {
          {"input_data_0_h", static_cast<int>(ctx.input_shapes[0][1])},
          {"input_data_0_w", static_cast<int>(ctx.input_shapes[0][2])},
          {"padding_w", attr.padding.prepended.w},
          {"padding_h", attr.padding.prepended.h},
          {"dilation_w", attr.dilations.w},
          {"dilation_h", attr.dilations.h},
          {"kernel_w", weights.w},
          {"kernel_h", weights.h},
          {"src_depth", DivideRoundUp(weights.i, 4)},
          {"stride", int2(attr.strides.w, attr.strides.h)},
      };
    } else {
      std::vector<int2> offsets;
      for (int h = 0; h < weights.h; ++h) {
        for (int w = 0; w < weights.w; ++w) {
          offsets.emplace_back(w * attr.dilations.w - attr.padding.prepended.w,
                               h * attr.dilations.h - attr.padding.prepended.h);
        }
      }
      parameters = {
          {"input_data_0_h", static_cast<int>(ctx.input_shapes[0][1])},
          {"input_data_0_w", static_cast<int>(ctx.input_shapes[0][2])},
          {"offsets_count", offsets_count},
          {"offsets", offsets},
          {"src_depth", DivideRoundUp(weights.i, 4)},
          {"stride", int2(attr.strides.w, attr.strides.h)},
      };
    }

    // at least one padding is not empty
    bool non_empty_padding =
        attr.padding.appended.h != 0 || attr.padding.appended.w != 0 ||
        attr.padding.prepended.h != 0 || attr.padding.prepended.w != 0;

    std::vector<std::pair<std::string, Object>> objects = {
        {"weights", MakeReadonlyObject(Get3DSizeForPHWO4I4(attr.weights.shape),
                                       ConvertToPHWO4I4(attr.weights))}};

    std::string source;
    if (offsets_count_too_large) {
      source = R"(
      int i = 0;
      for (int ky = 0; ky < $kernel_h$; ky++) {
        for (int kx = 0; kx < $kernel_w$; kx++, i++) {
          ivec2 coord = gid.xy * $stride$ + ivec2(kx * $dilation_w$ - $padding_w$, ky * $dilation_h$ - $padding_h$);)";
    } else {
      source = R"(
        for (int i = 0; i < $offsets_count$; ++i) {
          ivec2 coord = gid.xy * $stride$ + $offsets[i]$;)";
    }
    if (non_empty_padding) {
      source += R"(
        if (coord.x < 0 || coord.y < 0 || coord.x >= $input_data_0_w$ || coord.y >= $input_data_0_h$) {
          continue;
        })";
    }
    source += R"(
          for (int l = 0; l < $src_depth$; ++l) {
            vec4 input_ = $input_data_0[coord.x, coord.y, l]$;
            value_0.x += dot(input_, $weights[l * 4 + 0, i, gid.z]$);
            value_0.y += dot(input_, $weights[l * 4 + 1, i, gid.z]$);
            value_0.z += dot(input_, $weights[l * 4 + 2, i, gid.z]$);
            value_0.w += dot(input_, $weights[l * 4 + 3, i, gid.z]$);
          }
        }
)";
    if (offsets_count_too_large) {
      source += R"(
      }
)";
    }
    if (!attr.bias.data.empty()) {
      source += "value_0 += $bias[gid.z]$;\n";
      objects.push_back({"bias", MakeReadonlyObject(attr.bias.data)});
    }

    *generated_code = {
        /*parameters=*/std::move(parameters),
        /*objects=*/std::move(objects),
        /*shared_variables=*/{},
        /*workload=*/uint3(),
        /*workgroup=*/
        GetIdealWorkgroupIfPossible(
            *ctx.gpu_info, OperationType::CONVOLUTION_2D,
            HW(weights.h, weights.w), attr.strides, uint3(0, 0, 0),
            OHWI(weights.o, ctx.input_shapes[0][1], ctx.input_shapes[0][2],
                 ctx.input_shapes[0][3])),
        /*source_code=*/std::move(source),
        /*input=*/IOStructure::ONLY_DEFINITIONS,
        /*output=*/IOStructure::AUTO,
    };
    return absl::OkStatus();
  }
};

int SelectMultiplier(int32_t input_width,
                     const NodeShader::GenerationContext& ctx) {
  std::vector<int> multipliers = {4, 2};
  if (ctx.gpu_info->IsAMD()) {
    return 1;
  }
  if (!ctx.compiler_options.allow_precision_loss && ctx.gpu_info->IsMali()) {
    multipliers = {2};
  }
  for (int i : multipliers) {
    if (input_width % i == 0) {
      return i;
    }
  }
  return 1;
}

class Convolution1x1 : public NodeShader {
 public:
  absl::Status GenerateCode(const GenerationContext& ctx,
                            GeneratedCode* generated_code) const final {
    if (ctx.input_shapes.size() != 1) {
      return absl::UnimplementedError(
          "Convolution does not support more than 1 runtime tensor");
    }
    const auto& attr =
        absl::any_cast<const Convolution2DAttributes&>(ctx.op_attr);
    if (attr.weights.shape.h != 1 || attr.weights.shape.w != 1) {
      return absl::UnimplementedError("Height and width should be 1.");
    }
    if (attr.dilations.h != 1 || attr.dilations.w != 1) {
      return absl::UnimplementedError("Dilations are not supported.");
    }
    if (attr.strides.h != 1 || attr.strides.w != 1) {
      return absl::UnimplementedError("Strides are not supported.");
    }
    if (attr.padding.appended.h != 0 || attr.padding.appended.w != 0 ||
        attr.padding.prepended.h != 0 || attr.padding.prepended.w != 0) {
      return absl::UnimplementedError("Padding is not supported.");
    }

    int multiplier = SelectMultiplier(ctx.input_shapes[0][2], ctx);

    std::vector<Variable> parameters = {
        {"src_depth",
         DivideRoundUp(static_cast<int>(ctx.input_shapes[0][3]), 4)},
    };

    std::vector<std::pair<std::string, Object>> objects = {
        {"weights",
         MakeReadonlyObject(uint3(4, DivideRoundUp(attr.weights.shape.i, 4),
                                  DivideRoundUp(attr.weights.shape.o, 4)),
                            ConvertToPHWO4I4(attr.weights))}};
    std::string source;
    for (int i = 0; i < multiplier; i++) {
      absl::StrAppend(&source, "highp vec4 result", i, " = vec4(0);\n");
    }
    absl::StrAppend(&source, "highp vec4 f;\n");
    absl::StrAppend(&source, "for (int l = 0; l < $src_depth$; ++l) {\n");
    for (int i = 0; i < multiplier; i++) {
      absl::StrAppend(&source, "  highp vec4 input", i,
                      " = $input_data_0[gid.x * ", multiplier, " + ", i,
                      ",gid.y,l]$;\n");
    }
    for (int k = 0; k < 4; k++) {
      absl::StrAppend(&source, "  f = $weights[", k, ", l, gid.z]$;\n");
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "  result", i, "[", k, "] += dot(input", i,
                        ", f);\n");
      }
    }
    absl::StrAppend(&source, "}\n");
    if (!attr.bias.data.empty()) {
      objects.push_back({"bias", MakeReadonlyObject(attr.bias.data)});
      absl::StrAppend(&source, "highp vec4 b = $bias[gid.z]$;\n");
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "result", i, " += b;\n");
      }
    }
    if (multiplier != 1) {
      for (int i = 0; i < multiplier; i++) {
        absl::StrAppend(&source, "$inplace_update:result", i, "$\n");
        absl::StrAppend(&source, "$output_data_0[gid.x * ", multiplier, " + ",
                        i, ",gid.y,gid.z] = result", i, "$;\n");
      }
    } else {
      absl::StrAppend(&source, "value_0 = result0;\n");
    }

    auto dst_depth = DivideRoundUp(ctx.output_shapes[0][3], 4);
    uint3 workgroup = uint3(16, 16, 1);
    if (ctx.gpu_info->IsAdreno()) {
      if (dst_depth >= 2) {
        workgroup = uint3(8, 8, 2);
      }
      if (dst_depth >= 4) {
        workgroup = uint3(4, 8, 4);
      }
      if (dst_depth >= 8) {
        workgroup = uint3(4, 4, 8);
      }
      if (dst_depth >= 32) {
        workgroup = uint3(4, 4, 16);
      }
      if (dst_depth >= 64) {
        workgroup = uint3(2, 8, 16);
      }
    } else {
      if (dst_depth >= 2) {
        workgroup = uint3(16, 8, 2);
      }
      if (dst_depth >= 4) {
        workgroup = uint3(16, 4, 4);
      }
      if (dst_depth >= 8) {
        workgroup = uint3(8, 4, 8);
      }
      if (dst_depth >= 32) {
        workgroup = uint3(8, 4, 8);
      }
      if (dst_depth >= 64) {
        workgroup = uint3(8, 4, 8);
      }
    }
    *generated_code = {
        /*parameters=*/std::move(parameters),
        /*objects=*/std::move(objects),
        /*shared_variables=*/{},
        /*workload=*/
        uint3(ctx.output_shapes[0][2] / multiplier, ctx.output_shapes[0][1],
              DivideRoundUp(ctx.output_shapes[0][3], 4)),
        /*workgroup=*/
        GetIdealWorkgroupIfPossible(
            *ctx.gpu_info, OperationType::CONVOLUTION_2D,
            HW(attr.weights.shape.h, attr.weights.shape.w), attr.strides,
            workgroup,
            OHWI(attr.weights.shape.o, ctx.input_shapes[0][1],
                 ctx.input_shapes[0][2], ctx.input_shapes[0][3])),
        /*source_code=*/std::move(source),
        /*input=*/IOStructure::ONLY_DEFINITIONS,
        /*output=*/multiplier == 1 ? IOStructure::AUTO
                                   : IOStructure::ONLY_DEFINITIONS,
    };
    return absl::OkStatus();
  }
};

}  // namespace

std::unique_ptr<NodeShader> NewConvolutionNodeShader() {
  return absl::make_unique<Convolution>();
}

std::unique_ptr<NodeShader> NewConvolution1x1NodeShader() {
  return absl::make_unique<Convolution1x1>();
}

}  // namespace gl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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
 *
 * 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.
 *
 */

// Local VOTCA includes
#include <votca/tools/getline.h>
#include "votca/xtp/topology.h"

// Local private VOTCA includes
#include "vaverage.h"

namespace votca {
namespace xtp {

void VAverage::ParseOptions(const tools::Property& options) {

  _ratefile = options.get(".ratefile").as<std::string>();
  _occfile = options.get(".occfile").as<std::string>();
  _outputfile = options.get(".outputfile").as<std::string>();
}

std::vector<double> VAverage::ReadOccfile(std::string filename) const {
  std::vector<double> result;
  std::ifstream intt;
  intt.open(filename);
  if (!intt.is_open()) {
    throw std::runtime_error("File:" + filename + " could not be opened");
  }
  std::string line;
  Index id = 0;
  while (intt.good()) {

    tools::getline(intt, line);
    std::vector<std::string> split;
    tools::Tokenizer toker(line, " \t");
    toker.ToVector(split);
    if (!split.size() || split[0] == "#" || split[0].substr(0, 1) == "#") {
      continue;
    }
    if (split.size() != 2) {
      throw std::runtime_error("Row should only contain id and occupation");
    }

    Index id_readin = std::stoi(split[0]);
    if (id_readin != id) {
      throw std::runtime_error("Ids should be sorted and start at zero.");
    }
    id++;
    result.push_back(std::stod(split[1]));
  }
  return result;
}

std::vector<Rate_Engine::PairRates> VAverage::ReadRatefile(
    std::string filename) const {
  std::vector<Rate_Engine::PairRates> result;
  std::ifstream intt;
  intt.open(filename);
  if (!intt.is_open()) {
    throw std::runtime_error("File:" + filename + " could not be opened");
  }
  Index id = 0;
  std::string line;
  while (intt.good()) {

    tools::getline(intt, line);
    std::vector<std::string> split;
    tools::Tokenizer toker(line, " \t");
    toker.ToVector(split);
    if (!split.size() || split[0] == "#" || split[0].substr(0, 1) == "#") {
      continue;
    }
    if (split.size() != 5) {
      throw std::runtime_error(
          "Row should only contain pairid,segid1,segid2 ,rate12,rate21");
    }

    Index id_readin = std::stoi(split[0]);
    if (id_readin != id) {
      throw std::runtime_error("Ids should be sorted and start at zero.");
    }
    id++;
    Rate_Engine::PairRates pair;
    pair.rate12 = std::stod(split[3]);
    pair.rate21 = std::stod(split[4]);
    result.push_back(pair);
  }
  return result;
}

bool VAverage::Evaluate(Topology& top) {
  std::cout << std::endl
            << "... ... Computing velocity average for all sites\n";
  std::cout << "Reading in site occupations from " << _occfile << std::endl;
  std::vector<double> occ = ReadOccfile(_occfile);
  if (top.Segments().size() != occ.size()) {
    throw std::runtime_error(
        "Number of occupations is" + std::to_string(occ.size()) +
        " Topology has size:" + std::to_string(top.Segments().size()));
  }
  std::cout << "Reading in rates from " << _ratefile << std::endl;
  std::vector<Rate_Engine::PairRates> rates = ReadRatefile(_ratefile);
  if (top.NBList().size() != Index(rates.size())) {
    throw std::runtime_error(
        "Number of pairs in file is" + std::to_string(rates.size()) +
        " Topology has size:" + std::to_string(top.NBList().size()));
  }
  std::vector<Eigen::Vector3d> velocities =
      std::vector<Eigen::Vector3d>(occ.size(), Eigen::Vector3d::Zero());
  for (const QMPair* pair : top.NBList()) {
    Index id1 = pair->Seg1()->getId();
    Index id2 = pair->Seg1()->getId();
    Index pairid = pair->getId();
    double p1 = occ[id1];
    double p2 = occ[id2];
    double w12 = rates[pairid].rate12;
    double w21 = rates[pairid].rate21;
    const Eigen::Vector3d& dR12 =
        pair->R();  // points from seg. (1) to seg. (2)
    // Split current symmetrically among sites (1) and (2)
    Eigen::Vector3d v_12_21 = 0.5 * (p1 * w12 - p2 * w21) * dR12;
    velocities[id1] += v_12_21;
    velocities[id2] += v_12_21;
  }

  std::ofstream ofs;
  ofs.open(_outputfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("Bad file handle: " + _outputfile);
  }
  ofs << "# 1   |   2     |  3 4 5       |   6  7  8         |" << std::endl;
  ofs << "# ----|---------|--------------|-------------------|" << std::endl;
  ofs << "# ID  |   NAME  |  X Y Z [nm]  |   VX VY VZ [nm/s]  |" << std::endl;
  for (const Segment& seg : top.Segments()) {
    const Eigen::Vector3d r = seg.getPos() * tools::conv::bohr2nm;
    const Eigen::Vector3d v = velocities[seg.getId()] * tools::conv::bohr2nm;
    ofs << (boost::format("%1$4d %2$-10s %3$+1.7e %4$+1.7e "
                          "%5$+1.7e %6$+1.7e %7$+1.7e %8$+1.7e") %
            seg.getId() % seg.getType() % r.x() % r.y() % r.z() % v.x() %
            v.y() % v.z())
        << std::endl;
  }
  std::cout << "Writing velocities to " << _outputfile << std::endl;
  return true;
}

}  // namespace xtp
}  // namespace votca
<commit_msg>Format code using clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)<commit_after>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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
 *
 * 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.
 *
 */

// Local VOTCA includes
#include "votca/xtp/topology.h"
#include <votca/tools/getline.h>

// Local private VOTCA includes
#include "vaverage.h"

namespace votca {
namespace xtp {

void VAverage::ParseOptions(const tools::Property& options) {

  _ratefile = options.get(".ratefile").as<std::string>();
  _occfile = options.get(".occfile").as<std::string>();
  _outputfile = options.get(".outputfile").as<std::string>();
}

std::vector<double> VAverage::ReadOccfile(std::string filename) const {
  std::vector<double> result;
  std::ifstream intt;
  intt.open(filename);
  if (!intt.is_open()) {
    throw std::runtime_error("File:" + filename + " could not be opened");
  }
  std::string line;
  Index id = 0;
  while (intt.good()) {

    tools::getline(intt, line);
    std::vector<std::string> split;
    tools::Tokenizer toker(line, " \t");
    toker.ToVector(split);
    if (!split.size() || split[0] == "#" || split[0].substr(0, 1) == "#") {
      continue;
    }
    if (split.size() != 2) {
      throw std::runtime_error("Row should only contain id and occupation");
    }

    Index id_readin = std::stoi(split[0]);
    if (id_readin != id) {
      throw std::runtime_error("Ids should be sorted and start at zero.");
    }
    id++;
    result.push_back(std::stod(split[1]));
  }
  return result;
}

std::vector<Rate_Engine::PairRates> VAverage::ReadRatefile(
    std::string filename) const {
  std::vector<Rate_Engine::PairRates> result;
  std::ifstream intt;
  intt.open(filename);
  if (!intt.is_open()) {
    throw std::runtime_error("File:" + filename + " could not be opened");
  }
  Index id = 0;
  std::string line;
  while (intt.good()) {

    tools::getline(intt, line);
    std::vector<std::string> split;
    tools::Tokenizer toker(line, " \t");
    toker.ToVector(split);
    if (!split.size() || split[0] == "#" || split[0].substr(0, 1) == "#") {
      continue;
    }
    if (split.size() != 5) {
      throw std::runtime_error(
          "Row should only contain pairid,segid1,segid2 ,rate12,rate21");
    }

    Index id_readin = std::stoi(split[0]);
    if (id_readin != id) {
      throw std::runtime_error("Ids should be sorted and start at zero.");
    }
    id++;
    Rate_Engine::PairRates pair;
    pair.rate12 = std::stod(split[3]);
    pair.rate21 = std::stod(split[4]);
    result.push_back(pair);
  }
  return result;
}

bool VAverage::Evaluate(Topology& top) {
  std::cout << std::endl
            << "... ... Computing velocity average for all sites\n";
  std::cout << "Reading in site occupations from " << _occfile << std::endl;
  std::vector<double> occ = ReadOccfile(_occfile);
  if (top.Segments().size() != occ.size()) {
    throw std::runtime_error(
        "Number of occupations is" + std::to_string(occ.size()) +
        " Topology has size:" + std::to_string(top.Segments().size()));
  }
  std::cout << "Reading in rates from " << _ratefile << std::endl;
  std::vector<Rate_Engine::PairRates> rates = ReadRatefile(_ratefile);
  if (top.NBList().size() != Index(rates.size())) {
    throw std::runtime_error(
        "Number of pairs in file is" + std::to_string(rates.size()) +
        " Topology has size:" + std::to_string(top.NBList().size()));
  }
  std::vector<Eigen::Vector3d> velocities =
      std::vector<Eigen::Vector3d>(occ.size(), Eigen::Vector3d::Zero());
  for (const QMPair* pair : top.NBList()) {
    Index id1 = pair->Seg1()->getId();
    Index id2 = pair->Seg1()->getId();
    Index pairid = pair->getId();
    double p1 = occ[id1];
    double p2 = occ[id2];
    double w12 = rates[pairid].rate12;
    double w21 = rates[pairid].rate21;
    const Eigen::Vector3d& dR12 =
        pair->R();  // points from seg. (1) to seg. (2)
    // Split current symmetrically among sites (1) and (2)
    Eigen::Vector3d v_12_21 = 0.5 * (p1 * w12 - p2 * w21) * dR12;
    velocities[id1] += v_12_21;
    velocities[id2] += v_12_21;
  }

  std::ofstream ofs;
  ofs.open(_outputfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("Bad file handle: " + _outputfile);
  }
  ofs << "# 1   |   2     |  3 4 5       |   6  7  8         |" << std::endl;
  ofs << "# ----|---------|--------------|-------------------|" << std::endl;
  ofs << "# ID  |   NAME  |  X Y Z [nm]  |   VX VY VZ [nm/s]  |" << std::endl;
  for (const Segment& seg : top.Segments()) {
    const Eigen::Vector3d r = seg.getPos() * tools::conv::bohr2nm;
    const Eigen::Vector3d v = velocities[seg.getId()] * tools::conv::bohr2nm;
    ofs << (boost::format("%1$4d %2$-10s %3$+1.7e %4$+1.7e "
                          "%5$+1.7e %6$+1.7e %7$+1.7e %8$+1.7e") %
            seg.getId() % seg.getType() % r.x() % r.y() % r.z() % v.x() %
            v.y() % v.z())
        << std::endl;
  }
  std::cout << "Writing velocities to " << _outputfile << std::endl;
  return true;
}

}  // namespace xtp
}  // namespace votca
<|endoftext|>


<commit_before>#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "turtlesim/Pose.h"
#include <sstream>

using namespace std;

ros::Publisher velocity_publisher;
ros::Subscriber pose_subscriber;
turtlesim::Pose turtlesim_pose;

const double PI = 3.14159265359;

void move(double speed, double distance, bool isForward);
void rotate(double angular_speed, double angle, bool cloclwise);
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message);
//void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance);

int main(int argc, char **argv)
{
    // Initiate new ROS node named "robosys_turtle"
    ros::init(argc, argv, "robosys_turtle");
    ros::NodeHandle n;
    double speed, angular_speed;
    double distance, angle;
    bool isForward, clockwise;

    velocity_publisher = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
    pose_subscriber = n.subscribe("/turtle1/pose", 10, poseCallback);
    ros::Rate loop_rate(0.5);
    rotate(2,PI,0);
    move(2,10,1);

    for(int i = 0; i < 2; i++){
      rotate(2, 2/PI, 0);
      move(3, 10, 1);
    }

    rotate(2,2PI,1);

    ros::spin();

    return 0;
}
void move(double speed, double distance, bool isForward)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    if (isForward)
        vel_msg.linear.x =abs(speed);
    else
        vel_msg.linear.x =-abs(speed);
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    vel_msg.angular.z =0;

    double t0 = ros::Time::now().toSec();
    double current_distance = 0.0;
    ros::Rate loop_rate(100);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_distance = speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();

    }while(current_distance<distance);

    vel_msg.linear.x =0;
    velocity_publisher.publish(vel_msg);
}

void rotate (double angular_speed, double relative_angle, bool clockwise)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    vel_msg.linear.x =0;
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    if (clockwise)
        vel_msg.angular.z =-abs(angular_speed);
    else
         vel_msg.angular.z =abs(angular_speed);

    double t0 = ros::Time::now().toSec();
    double current_angle = 0.0;
    ros::Rate loop_rate(1000);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_angle = angular_speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();
        //cout<<(t1-t0)<<", "<<current_angle <<", "<<relative_angle<<endl;
    }while(current_angle<relative_angle);
    vel_msg.angular.z =0;
    velocity_publisher.publish(vel_msg);
}

/*
void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance)
{
    //We implement a Proportional Controller. We need to go from (x,y) to (x',y'). Then, linear velocity v' = K ((x'-x)^2 + (y'-y)^2)^0.5 where K is the constant and ((x'-x)^2 + (y'-y)^2)^0.5 is the Euclidian distance. The steering angle theta = tan^-1(y'-y)/(x'-x) is the angle between these 2 points.
    geometry_msgs::Twist vel_msg;

    ros::Rate loop_rate(10);
    do{
        //linear velocity
        vel_msg.linear.x = 1.5*getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y);
        vel_msg.linear.y = 0;
        vel_msg.linear.z = 0;
        //angular velocity
        vel_msg.angular.x = 0;
        vel_msg.angular.y = 0;
        vel_msg.angular.z = 4*(atan2(goal_pose.y - turtlesim_pose.y, goal_pose.x - turtlesim_pose.x)-turtlesim_pose.theta);

        velocity_publisher.publish(vel_msg);

        ros::spinOnce();
        loop_rate.sleep();

    }while(getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y)>distance_tolerance);
    cout<<"end move goal"<<endl;
    vel_msg.linear.x = 0;
    vel_msg.angular.z = 0;
    velocity_publisher.publish(vel_msg);

}*/
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message)
{
    turtlesim_pose.x=pose_message->x;
    turtlesim_pose.y=pose_message->y;    turtlesim_pose.theta=pose_message->theta;
}
<commit_msg>Revert "Revert "write""<commit_after>#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "turtlesim/Pose.h"
#include <sstream>

using namespace std;

ros::Publisher velocity_publisher;
ros::Subscriber pose_subscriber;
turtlesim::Pose turtlesim_pose;

const double PI = 3.14159265359;

void move(double speed, double distance, bool isForward);
void rotate(double angular_speed, double angle, bool cloclwise);
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message);
void circle(double radius, double turn_angle, bool clockwise)

int main(int argc, char **argv)
{
    // Initiate new ROS node named "robosys_turtle"
    ros::init(argc, argv, "robosys_turtle");
    ros::NodeHandle n;
    double speed, angular_speed;
    double distance, angle;
    bool isForward, clockwise;

    velocity_publisher = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
    pose_subscriber = n.subscribe("/turtle1/pose", 10, poseCallback);
    ros::Rate loop_rate(0.5);
    rotate(2,PI,0);
    move(2,10,1);

    for(int i = 0; i < 2; i++){
      rotate(2, 2/PI, 0);
      circle(1,PI,0);

    }

    rotate(2,2PI,1);

    ros::spin();

    return 0;
}
void move(double speed, double distance, bool isForward)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    if (isForward)
        vel_msg.linear.x =abs(speed);
    else
        vel_msg.linear.x =-abs(speed);
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    vel_msg.angular.z =0;

    double t0 = ros::Time::now().toSec();
    double current_distance = 0.0;
    ros::Rate loop_rate(100);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_distance = speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();

    }while(current_distance<distance);

    vel_msg.linear.x =0;
    velocity_publisher.publish(vel_msg);
}

void rotate (double angular_speed, double relative_angle, bool clockwise)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    vel_msg.linear.x =0;
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    if (clockwise)
        vel_msg.angular.z =-abs(angular_speed);
    else
         vel_msg.angular.z =abs(angular_speed);

    double t0 = ros::Time::now().toSec();
    double current_angle = 0.0;
    ros::Rate loop_rate(1000);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_angle = angular_speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();
        //cout<<(t1-t0)<<", "<<current_angle <<", "<<relative_angle<<endl;
    }while(current_angle<relative_angle);
    vel_msg.angular.z =0;
    velocity_publisher.publish(vel_msg);
}

void circle(double radius, double turn_angle, bool clockwise)
{
     double t0;
     double current_angle = 0.0;

     geometry_msgs::Twist vel_msg;
     //set a rondom linear velocity in the x-axis
     vel_msg.linear.x = 0;
     vel_msg.linear.y = 0;
     vel_msg.linear.z = 0;
     //set a rondom angular velocity inthe y-axis
     vel_msg.angular.x = 0;
     vel_msg.angular.y = 0;
     vel_msg.angular.z = 0;
     t0 = ros::Time::now().toSec();
     ros::Rate loop_rate(1000);

     if(clockwise){
          vel_msg.angular.z = abs(turn_angle);
          vel_msg.linear.x = abs(radius * PI);
     }
     else {
          vel_msg.angular.z = abs(turn_angle);
          vel_msg.linear.x = abs(radius * PI);
     }

     do{
          velocity_publisher.publish(vel_msg);
          t1 = ros::Time::now().toSec();
          current_angle = turn_angle * (t1 - t0);
          loop_rate.sleep();
     }while(current_angle < turn_angle);

     vel_msg.angular.z = 0;
     vel_msg.linear.x = 0;
     velocity_publisher.publish(vel_msg);
}
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message)
{
    turtlesim_pose.x=pose_message->x;
    turtlesim_pose.y=pose_message->y;    turtlesim_pose.theta=pose_message->theta;
}
<|endoftext|>


<commit_before>#include "utils.hpp"
#include "mapnik_geometry.hpp"
#include "mapnik_projection.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/geometry_reprojection.hpp>
#include <mapnik/util/geometry_to_geojson.hpp>
#include <mapnik/geometry_reprojection.hpp>
#include <mapnik/util/geometry_to_wkt.hpp>
#include <mapnik/util/geometry_to_wkb.hpp>

Persistent<FunctionTemplate> Geometry::constructor;

void Geometry::Initialize(Handle<Object> target) {

    NanScope();

    Local<FunctionTemplate> lcons = NanNew<FunctionTemplate>(Geometry::New);
    lcons->InstanceTemplate()->SetInternalFieldCount(1);
    lcons->SetClassName(NanNew("Geometry"));

    NODE_SET_PROTOTYPE_METHOD(lcons, "extent", extent);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toWKB", toWKB);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toWKT", toWKT);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toJSON", toJSON);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toJSONSync", toJSONSync);
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "Point",mapnik::datasource_geometry_t::Point)
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "LineString",mapnik::datasource_geometry_t::LineString)
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "Polygon",mapnik::datasource_geometry_t::Polygon)
    target->Set(NanNew("Geometry"), lcons->GetFunction());
    NanAssignPersistent(constructor, lcons);
}

Geometry::Geometry(mapnik::feature_ptr f) :
    node::ObjectWrap(),
    feat_(f) {}

Geometry::~Geometry()
{
}

NAN_METHOD(Geometry::New)
{
    NanScope();
    if (args[0]->IsExternal())
    {
        Local<External> ext = args[0].As<External>();
        void* ptr = ext->Value();
        Geometry* g =  static_cast<Geometry*>(ptr);
        g->Wrap(args.This());
        NanReturnValue(args.This());
    }
    else
    {
        NanThrowError("a mapnik.Geometry cannot be created directly - it is only available via a mapnik.Feature instance");
        NanReturnUndefined();
    }
    NanReturnValue(args.This());
}

Handle<Value> Geometry::NewInstance(mapnik::feature_ptr f) {
    NanEscapableScope();
    Geometry* g = new Geometry(f);
    Handle<Value> ext = NanNew<External>(g);
    Handle<Object> obj = NanNew(constructor)->GetFunction()->NewInstance(1, &ext);
    return NanEscapeScope(obj);
}

NAN_METHOD(Geometry::toJSONSync)
{
    NanScope();
    NanReturnValue(_toJSONSync(args));
}

bool to_geojson_projected(std::string & json,
                          mapnik::geometry::geometry<double> const& geom,
                          mapnik::proj_transform const& prj_trans)
{
    unsigned int n_err = 0;
    mapnik::geometry::geometry<double> projected_geom = mapnik::geometry::reproject_copy(geom,prj_trans,n_err);
    if (n_err > 0) return false;
    return mapnik::util::to_geojson(json,projected_geom);
}

Local<Value> Geometry::_toJSONSync(_NAN_METHOD_ARGS) {
    NanEscapableScope();
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    std::string json;
    if (args.Length() < 1)
    {
        if (!mapnik::util::to_geojson(json,g->feat_->get_geometry()))
        {
            // Fairly certain this situation can never be reached but
            // leaving it none the less
            /* LCOV_EXCL_START */
            NanThrowError("Failed to generate GeoJSON");
            return NanEscapeScope(NanUndefined());
            /* LCOV_EXCL_END */
        }
    }
    else
    {
        if (!args[0]->IsObject()) {
            NanThrowTypeError("optional first arg must be an options object");
            return NanEscapeScope(NanUndefined());
        }
        Local<Object> options = args[0]->ToObject();
        if (options->Has(NanNew("transform")))
        {
            Local<Value> bound_opt = options->Get(NanNew("transform"));
            if (!bound_opt->IsObject()) {
                NanThrowTypeError("'transform' must be an object");
                return NanEscapeScope(NanUndefined());
            }

            Local<Object> obj = bound_opt->ToObject();
            if (obj->IsNull() || obj->IsUndefined() || !NanNew(ProjTransform::constructor)->HasInstance(obj)) {
                NanThrowTypeError("mapnik.ProjTransform expected as first arg");
                return NanEscapeScope(NanUndefined());
            }
            ProjTransform* tr = node::ObjectWrap::Unwrap<ProjTransform>(obj);
            mapnik::proj_transform const& prj_trans = *tr->get();
            mapnik::geometry::geometry<double> const& geom = g->feat_->get_geometry();
            if (!to_geojson_projected(json,geom,prj_trans))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                /* LCOV_EXCL_START */
                NanThrowError("Failed to generate GeoJSON");
                return NanEscapeScope(NanUndefined());
                /* LCOV_EXCL_END */
            }
        }
    }
    return NanEscapeScope(NanNew(json));
}

struct to_json_baton {
    uv_work_t request;
    Geometry* g;
    ProjTransform* tr;
    bool error;
    std::string result;
    Persistent<Function> cb;
};

NAN_METHOD(Geometry::toJSON)
{
    NanScope();
    if ((args.Length() < 1) || !args[args.Length()-1]->IsFunction()) {
        NanReturnValue(_toJSONSync(args));
    }

    to_json_baton *closure = new to_json_baton();
    closure->request.data = closure;
    closure->g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    closure->error = false;
    closure->tr = nullptr;
    if (args.Length() > 1)
    {
        if (!args[0]->IsObject()) {
            NanThrowTypeError("optional first arg must be an options object");
            NanReturnUndefined();
        }
        Local<Object> options = args[0]->ToObject();
        if (options->Has(NanNew("transform")))
        {
            Local<Value> bound_opt = options->Get(NanNew("transform"));
            if (!bound_opt->IsObject()) {
                NanThrowTypeError("'transform' must be an object");
                NanReturnUndefined();
            }

            Local<Object> obj = bound_opt->ToObject();
            if (obj->IsNull() || obj->IsUndefined() || !NanNew(ProjTransform::constructor)->HasInstance(obj)) {
                NanThrowTypeError("mapnik.ProjTransform expected as first arg");
                NanReturnUndefined();
            }
            closure->tr = node::ObjectWrap::Unwrap<ProjTransform>(obj);
            closure->tr->_ref();
        }
    }
    Local<Value> callback = args[args.Length()-1];
    NanAssignPersistent(closure->cb, callback.As<Function>());
    uv_queue_work(uv_default_loop(), &closure->request, to_json, (uv_after_work_cb)after_to_json);
    closure->g->Ref();
    NanReturnUndefined();
}

void Geometry::to_json(uv_work_t* req)
{
    to_json_baton *closure = static_cast<to_json_baton *>(req->data);
    try
    {
        if (closure->tr)
        {
            mapnik::proj_transform const& prj_trans = *closure->tr->get();
            mapnik::geometry::geometry<double> const& geom = closure->g->feat_->get_geometry();
            if (!to_geojson_projected(closure->result,geom,prj_trans))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                // LCOV_EXCL_START
                closure->error = true;
                closure->result = "Failed to generate GeoJSON";
                // LCOV_EXCL_END
            }
        }
        else
        {
            if (!mapnik::util::to_geojson(closure->result,closure->g->feat_->get_geometry()))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                /* LCOV_EXCL_START */
                closure->error = true;
                closure->result = "Failed to generate GeoJSON";
                /* LCOV_EXCL_END */
            }
        }
    }
    catch (std::exception const& ex)
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        closure->error = true;
        closure->result = ex.what();
        /* LCOV_EXCL_END */
    }
}

void Geometry::after_to_json(uv_work_t* req)
{
    NanScope();
    to_json_baton *closure = static_cast<to_json_baton *>(req->data);
    if (closure->error)
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        Local<Value> argv[1] = { NanError(closure->result.c_str()) };
        NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(closure->cb), 1, argv);
        /* LCOV_EXCL_END */
    }
    else
    {
        Local<Value> argv[2] = { NanNull(), NanNew(closure->result) };
        NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(closure->cb), 2, argv);
    }
    closure->g->Unref();
    if (closure->tr) {
        closure->tr->_unref();
    }
    NanDisposePersistent(closure->cb);
    delete closure;
}

NAN_METHOD(Geometry::extent)
{
    NanScope();
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    Local<Array> a = NanNew<Array>(4);
    mapnik::box2d<double> const& e = g->feat_->envelope();
    a->Set(0, NanNew<Number>(e.minx()));
    a->Set(1, NanNew<Number>(e.miny()));
    a->Set(2, NanNew<Number>(e.maxx()));
    a->Set(3, NanNew<Number>(e.maxy()));
    NanReturnValue(a);
}

NAN_METHOD(Geometry::toWKT)
{
    NanScope();
    std::string wkt;
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    if (!mapnik::util::to_wkt(wkt, g->feat_->get_geometry()))
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        NanThrowError("Failed to generate WKT");
        NanReturnUndefined();
        /* LCOV_EXCL_END */
    }
    NanReturnValue(NanNew(wkt.c_str()));
}

NAN_METHOD(Geometry::toWKB)
{
    NanScope();
    std::string wkt;
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(g->feat_->get_geometry(), mapnik::wkbNDR);
    if (!wkb)
    {
        NanThrowError("Failed to generate WKB - geometry likely null");
        NanReturnUndefined();
    }
    NanReturnValue(NanNewBufferHandle(wkb->buffer(), wkb->size()));
}
<commit_msg>remove dupe include [skip ci]<commit_after>#include "utils.hpp"
#include "mapnik_geometry.hpp"
#include "mapnik_projection.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/geometry_reprojection.hpp>
#include <mapnik/util/geometry_to_geojson.hpp>
#include <mapnik/util/geometry_to_wkt.hpp>
#include <mapnik/util/geometry_to_wkb.hpp>

Persistent<FunctionTemplate> Geometry::constructor;

void Geometry::Initialize(Handle<Object> target) {

    NanScope();

    Local<FunctionTemplate> lcons = NanNew<FunctionTemplate>(Geometry::New);
    lcons->InstanceTemplate()->SetInternalFieldCount(1);
    lcons->SetClassName(NanNew("Geometry"));

    NODE_SET_PROTOTYPE_METHOD(lcons, "extent", extent);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toWKB", toWKB);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toWKT", toWKT);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toJSON", toJSON);
    NODE_SET_PROTOTYPE_METHOD(lcons, "toJSONSync", toJSONSync);
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "Point",mapnik::datasource_geometry_t::Point)
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "LineString",mapnik::datasource_geometry_t::LineString)
    NODE_MAPNIK_DEFINE_CONSTANT(lcons->GetFunction(),
                                "Polygon",mapnik::datasource_geometry_t::Polygon)
    target->Set(NanNew("Geometry"), lcons->GetFunction());
    NanAssignPersistent(constructor, lcons);
}

Geometry::Geometry(mapnik::feature_ptr f) :
    node::ObjectWrap(),
    feat_(f) {}

Geometry::~Geometry()
{
}

NAN_METHOD(Geometry::New)
{
    NanScope();
    if (args[0]->IsExternal())
    {
        Local<External> ext = args[0].As<External>();
        void* ptr = ext->Value();
        Geometry* g =  static_cast<Geometry*>(ptr);
        g->Wrap(args.This());
        NanReturnValue(args.This());
    }
    else
    {
        NanThrowError("a mapnik.Geometry cannot be created directly - it is only available via a mapnik.Feature instance");
        NanReturnUndefined();
    }
    NanReturnValue(args.This());
}

Handle<Value> Geometry::NewInstance(mapnik::feature_ptr f) {
    NanEscapableScope();
    Geometry* g = new Geometry(f);
    Handle<Value> ext = NanNew<External>(g);
    Handle<Object> obj = NanNew(constructor)->GetFunction()->NewInstance(1, &ext);
    return NanEscapeScope(obj);
}

NAN_METHOD(Geometry::toJSONSync)
{
    NanScope();
    NanReturnValue(_toJSONSync(args));
}

bool to_geojson_projected(std::string & json,
                          mapnik::geometry::geometry<double> const& geom,
                          mapnik::proj_transform const& prj_trans)
{
    unsigned int n_err = 0;
    mapnik::geometry::geometry<double> projected_geom = mapnik::geometry::reproject_copy(geom,prj_trans,n_err);
    if (n_err > 0) return false;
    return mapnik::util::to_geojson(json,projected_geom);
}

Local<Value> Geometry::_toJSONSync(_NAN_METHOD_ARGS) {
    NanEscapableScope();
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    std::string json;
    if (args.Length() < 1)
    {
        if (!mapnik::util::to_geojson(json,g->feat_->get_geometry()))
        {
            // Fairly certain this situation can never be reached but
            // leaving it none the less
            /* LCOV_EXCL_START */
            NanThrowError("Failed to generate GeoJSON");
            return NanEscapeScope(NanUndefined());
            /* LCOV_EXCL_END */
        }
    }
    else
    {
        if (!args[0]->IsObject()) {
            NanThrowTypeError("optional first arg must be an options object");
            return NanEscapeScope(NanUndefined());
        }
        Local<Object> options = args[0]->ToObject();
        if (options->Has(NanNew("transform")))
        {
            Local<Value> bound_opt = options->Get(NanNew("transform"));
            if (!bound_opt->IsObject()) {
                NanThrowTypeError("'transform' must be an object");
                return NanEscapeScope(NanUndefined());
            }

            Local<Object> obj = bound_opt->ToObject();
            if (obj->IsNull() || obj->IsUndefined() || !NanNew(ProjTransform::constructor)->HasInstance(obj)) {
                NanThrowTypeError("mapnik.ProjTransform expected as first arg");
                return NanEscapeScope(NanUndefined());
            }
            ProjTransform* tr = node::ObjectWrap::Unwrap<ProjTransform>(obj);
            mapnik::proj_transform const& prj_trans = *tr->get();
            mapnik::geometry::geometry<double> const& geom = g->feat_->get_geometry();
            if (!to_geojson_projected(json,geom,prj_trans))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                /* LCOV_EXCL_START */
                NanThrowError("Failed to generate GeoJSON");
                return NanEscapeScope(NanUndefined());
                /* LCOV_EXCL_END */
            }
        }
    }
    return NanEscapeScope(NanNew(json));
}

struct to_json_baton {
    uv_work_t request;
    Geometry* g;
    ProjTransform* tr;
    bool error;
    std::string result;
    Persistent<Function> cb;
};

NAN_METHOD(Geometry::toJSON)
{
    NanScope();
    if ((args.Length() < 1) || !args[args.Length()-1]->IsFunction()) {
        NanReturnValue(_toJSONSync(args));
    }

    to_json_baton *closure = new to_json_baton();
    closure->request.data = closure;
    closure->g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    closure->error = false;
    closure->tr = nullptr;
    if (args.Length() > 1)
    {
        if (!args[0]->IsObject()) {
            NanThrowTypeError("optional first arg must be an options object");
            NanReturnUndefined();
        }
        Local<Object> options = args[0]->ToObject();
        if (options->Has(NanNew("transform")))
        {
            Local<Value> bound_opt = options->Get(NanNew("transform"));
            if (!bound_opt->IsObject()) {
                NanThrowTypeError("'transform' must be an object");
                NanReturnUndefined();
            }

            Local<Object> obj = bound_opt->ToObject();
            if (obj->IsNull() || obj->IsUndefined() || !NanNew(ProjTransform::constructor)->HasInstance(obj)) {
                NanThrowTypeError("mapnik.ProjTransform expected as first arg");
                NanReturnUndefined();
            }
            closure->tr = node::ObjectWrap::Unwrap<ProjTransform>(obj);
            closure->tr->_ref();
        }
    }
    Local<Value> callback = args[args.Length()-1];
    NanAssignPersistent(closure->cb, callback.As<Function>());
    uv_queue_work(uv_default_loop(), &closure->request, to_json, (uv_after_work_cb)after_to_json);
    closure->g->Ref();
    NanReturnUndefined();
}

void Geometry::to_json(uv_work_t* req)
{
    to_json_baton *closure = static_cast<to_json_baton *>(req->data);
    try
    {
        if (closure->tr)
        {
            mapnik::proj_transform const& prj_trans = *closure->tr->get();
            mapnik::geometry::geometry<double> const& geom = closure->g->feat_->get_geometry();
            if (!to_geojson_projected(closure->result,geom,prj_trans))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                // LCOV_EXCL_START
                closure->error = true;
                closure->result = "Failed to generate GeoJSON";
                // LCOV_EXCL_END
            }
        }
        else
        {
            if (!mapnik::util::to_geojson(closure->result,closure->g->feat_->get_geometry()))
            {
                // Fairly certain this situation can never be reached but
                // leaving it none the less
                /* LCOV_EXCL_START */
                closure->error = true;
                closure->result = "Failed to generate GeoJSON";
                /* LCOV_EXCL_END */
            }
        }
    }
    catch (std::exception const& ex)
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        closure->error = true;
        closure->result = ex.what();
        /* LCOV_EXCL_END */
    }
}

void Geometry::after_to_json(uv_work_t* req)
{
    NanScope();
    to_json_baton *closure = static_cast<to_json_baton *>(req->data);
    if (closure->error)
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        Local<Value> argv[1] = { NanError(closure->result.c_str()) };
        NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(closure->cb), 1, argv);
        /* LCOV_EXCL_END */
    }
    else
    {
        Local<Value> argv[2] = { NanNull(), NanNew(closure->result) };
        NanMakeCallback(NanGetCurrentContext()->Global(), NanNew(closure->cb), 2, argv);
    }
    closure->g->Unref();
    if (closure->tr) {
        closure->tr->_unref();
    }
    NanDisposePersistent(closure->cb);
    delete closure;
}

NAN_METHOD(Geometry::extent)
{
    NanScope();
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    Local<Array> a = NanNew<Array>(4);
    mapnik::box2d<double> const& e = g->feat_->envelope();
    a->Set(0, NanNew<Number>(e.minx()));
    a->Set(1, NanNew<Number>(e.miny()));
    a->Set(2, NanNew<Number>(e.maxx()));
    a->Set(3, NanNew<Number>(e.maxy()));
    NanReturnValue(a);
}

NAN_METHOD(Geometry::toWKT)
{
    NanScope();
    std::string wkt;
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    if (!mapnik::util::to_wkt(wkt, g->feat_->get_geometry()))
    {
        // Fairly certain this situation can never be reached but
        // leaving it none the less
        /* LCOV_EXCL_START */
        NanThrowError("Failed to generate WKT");
        NanReturnUndefined();
        /* LCOV_EXCL_END */
    }
    NanReturnValue(NanNew(wkt.c_str()));
}

NAN_METHOD(Geometry::toWKB)
{
    NanScope();
    std::string wkt;
    Geometry* g = node::ObjectWrap::Unwrap<Geometry>(args.Holder());
    mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(g->feat_->get_geometry(), mapnik::wkbNDR);
    if (!wkb)
    {
        NanThrowError("Failed to generate WKB - geometry likely null");
        NanReturnUndefined();
    }
    NanReturnValue(NanNewBufferHandle(wkb->buffer(), wkb->size()));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef TEMPORARY_BUFFER_HH_
#define TEMPORARY_BUFFER_HH_

#include "deleter.hh"
#include "util/eclipse.hh"

// A temporary_buffer either points inside a larger buffer, or, if the requested size
// is too large, or if the larger buffer is scattered, contains its own storage.
template <typename CharType>
class temporary_buffer {
    static_assert(sizeof(CharType) == 1, "must buffer stream of bytes");
    CharType* _buffer;
    size_t _size;
    deleter _deleter;
public:
    explicit temporary_buffer(size_t size)
        : _buffer(static_cast<CharType*>(malloc(size * sizeof(CharType)))), _size(size)
        , _deleter(make_free_deleter(_buffer)) {
        if (!_buffer) {
            throw std::bad_alloc();
        }
    }
    //explicit temporary_buffer(CharType* borrow, size_t size) : _buffer(borrow), _size(size) {}
    temporary_buffer()
        : _buffer(nullptr)
        , _size(0) {}
    temporary_buffer(const temporary_buffer&) = delete;
    temporary_buffer(temporary_buffer&& x) : _buffer(x._buffer), _size(x._size), _deleter(std::move(x._deleter)) {
        x._buffer = nullptr;
        x._size = 0;
    }
    temporary_buffer(CharType* buf, size_t size, deleter d)
        : _buffer(buf), _size(size), _deleter(std::move(d)) {}
    void operator=(const temporary_buffer&) = delete;
    temporary_buffer& operator=(temporary_buffer&& x) {
        if (this != &x) {
            _buffer = x._buffer;
            _size = x._size;
            _deleter = std::move(x._deleter);
            x._buffer = nullptr;
            x._size = 0;
        }
        return *this;
    }
    const CharType* get() const { return _buffer; }
    CharType* get_write() { return _buffer; }
    size_t size() const { return _size; }
    const CharType* begin() { return _buffer; }
    const CharType* end() { return _buffer + _size; }
    temporary_buffer prefix(size_t size) && {
        auto ret = std::move(*this);
        ret._size = size;
        return ret;
    }
    CharType operator[](size_t pos) const {
        return _buffer[pos];
    }
    bool empty() const { return !size(); }
    operator bool() { return size(); }
    temporary_buffer share() {
        return temporary_buffer(_buffer, _size, _deleter.share());
    }
    temporary_buffer share(size_t pos, size_t len) {
        auto ret = share();
        ret._buffer += pos;
        ret._size = len;
        return ret;
    }
    void trim_front(size_t pos) {
        _buffer += pos;
        _size -= pos;
    }
    void trim(size_t pos) {
        _size = pos;
    }
    deleter release() {
        return std::move(_deleter);
    }
};

#endif /* TEMPORARY_BUFFER_HH_ */
<commit_msg>temporary_buffer: fix wrong oom check<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef TEMPORARY_BUFFER_HH_
#define TEMPORARY_BUFFER_HH_

#include "deleter.hh"
#include "util/eclipse.hh"

// A temporary_buffer either points inside a larger buffer, or, if the requested size
// is too large, or if the larger buffer is scattered, contains its own storage.
template <typename CharType>
class temporary_buffer {
    static_assert(sizeof(CharType) == 1, "must buffer stream of bytes");
    CharType* _buffer;
    size_t _size;
    deleter _deleter;
public:
    explicit temporary_buffer(size_t size)
        : _buffer(static_cast<CharType*>(malloc(size * sizeof(CharType)))), _size(size)
        , _deleter(make_free_deleter(_buffer)) {
        if (size && !_buffer) {
            throw std::bad_alloc();
        }
    }
    //explicit temporary_buffer(CharType* borrow, size_t size) : _buffer(borrow), _size(size) {}
    temporary_buffer()
        : _buffer(nullptr)
        , _size(0) {}
    temporary_buffer(const temporary_buffer&) = delete;
    temporary_buffer(temporary_buffer&& x) : _buffer(x._buffer), _size(x._size), _deleter(std::move(x._deleter)) {
        x._buffer = nullptr;
        x._size = 0;
    }
    temporary_buffer(CharType* buf, size_t size, deleter d)
        : _buffer(buf), _size(size), _deleter(std::move(d)) {}
    void operator=(const temporary_buffer&) = delete;
    temporary_buffer& operator=(temporary_buffer&& x) {
        if (this != &x) {
            _buffer = x._buffer;
            _size = x._size;
            _deleter = std::move(x._deleter);
            x._buffer = nullptr;
            x._size = 0;
        }
        return *this;
    }
    const CharType* get() const { return _buffer; }
    CharType* get_write() { return _buffer; }
    size_t size() const { return _size; }
    const CharType* begin() { return _buffer; }
    const CharType* end() { return _buffer + _size; }
    temporary_buffer prefix(size_t size) && {
        auto ret = std::move(*this);
        ret._size = size;
        return ret;
    }
    CharType operator[](size_t pos) const {
        return _buffer[pos];
    }
    bool empty() const { return !size(); }
    operator bool() { return size(); }
    temporary_buffer share() {
        return temporary_buffer(_buffer, _size, _deleter.share());
    }
    temporary_buffer share(size_t pos, size_t len) {
        auto ret = share();
        ret._buffer += pos;
        ret._size = len;
        return ret;
    }
    void trim_front(size_t pos) {
        _buffer += pos;
        _size -= pos;
    }
    void trim(size_t pos) {
        _size = pos;
    }
    deleter release() {
        return std::move(_deleter);
    }
};

#endif /* TEMPORARY_BUFFER_HH_ */
<|endoftext|>


<commit_before>/**
 * \file
 * \brief Main code block.
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "TestCaseGroup.hpp"
#include "testCases.hpp"

#include "distortos/distortosConfiguration.h"

#ifdef CONFIG_BOARD_LEDS_ENABLE

#include "distortos/board/leds.hpp"

#include "distortos/chip/ChipOutputPin.hpp"

#endif	// def CONFIG_BOARD_LEDS_ENABLE

#include "distortos/ThisThread.hpp"

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Main code block of test application
 *
 * Runs all test cases. The result is signaled with blinking of all board's LEDs:
 * - success - slow blinking, 1 Hz frequency,
 * - failure - fast blinking, 10 Hz frequency.
 * If the board doesn't provide LEDs, the result can be examined with the debugger by checking the value of "result"
 * variable.
 */

int main()
{
	// "volatile" to allow examination of the value with debugger - the variable will not be optimized out
	const volatile auto result = distortos::test::testCases.run();

	// next line is a good place for a breakpoint that will be hit right after test cases
	const auto duration = result == true ? std::chrono::milliseconds{500} : std::chrono::milliseconds{50};
	while (1)
	{
#ifdef CONFIG_BOARD_LEDS_ENABLE

		for (size_t ledIndex {}; ledIndex < distortos::board::totalLeds; ++ledIndex)
		{
			auto& led = distortos::board::leds[ledIndex];
			led.set(!led.get());
		}

#endif	// def CONFIG_BOARD_LEDS_ENABLE

		distortos::ThisThread::sleepFor(duration);
	}
}
<commit_msg>turn leds on immediately<commit_after>/**
 * \file
 * \brief Main code block.
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "TestCaseGroup.hpp"
#include "testCases.hpp"

#include "distortos/distortosConfiguration.h"

#ifdef CONFIG_BOARD_LEDS_ENABLE

#include "distortos/board/leds.hpp"

#include "distortos/chip/ChipOutputPin.hpp"

#endif	// def CONFIG_BOARD_LEDS_ENABLE

#include "distortos/ThisThread.hpp"

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Main code block of test application
 *
 * Runs all test cases. The result is signaled with blinking of all board's LEDs:
 * - success - slow blinking, 1 Hz frequency,
 * - failure - fast blinking, 10 Hz frequency.
 * If the board doesn't provide LEDs, the result can be examined with the debugger by checking the value of "result"
 * variable.
 */

int main()
{
#if defined(CONFIG_BOARD_LEDS_ENABLE)

	for (size_t ledIndex {}; ledIndex < distortos::board::totalLeds; ++ledIndex)
	{
		auto& led = distortos::board::leds[ledIndex];
		led.set(true);
	}

#endif	// def CONFIG_BOARD_LEDS_ENABLE

	// "volatile" to allow examination of the value with debugger - the variable will not be optimized out
	const volatile auto result = distortos::test::testCases.run();

	// next line is a good place for a breakpoint that will be hit right after test cases
	const auto duration = result == true ? std::chrono::milliseconds{500} : std::chrono::milliseconds{50};
	while (1)
	{
#ifdef CONFIG_BOARD_LEDS_ENABLE

		for (size_t ledIndex {}; ledIndex < distortos::board::totalLeds; ++ledIndex)
		{
			auto& led = distortos::board::leds[ledIndex];
			led.set(!led.get());
		}

#endif	// def CONFIG_BOARD_LEDS_ENABLE

		distortos::ThisThread::sleepFor(duration);
	}
}
<|endoftext|>


<commit_before>#include "utils.hpp"
#include "mapnik_geometry.hpp"

// mapnik
#include <mapnik/wkt/wkt_factory.hpp>

// boost
#include <boost/make_shared.hpp>

Persistent<FunctionTemplate> Geometry::constructor;

void Geometry::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Geometry::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Geometry"));

    NODE_SET_PROTOTYPE_METHOD(constructor, "extent", extent);
    NODE_SET_PROTOTYPE_METHOD(constructor, "type", type);

    NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                "Point",mapnik::Point)
        NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                    "LineString",mapnik::LineString)
        NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                    "Polygon",mapnik::Polygon)

        target->Set(String::NewSymbol("Geometry"),constructor->GetFunction());
}

Geometry::Geometry() :
    ObjectWrap(),
    this_() {}

Geometry::~Geometry()
{
}

Handle<Value> Geometry::New(const Arguments& args)
{
    HandleScope scope;
    //if (!args.IsConstructCall())
    //    return ThrowException(String::New("Cannot call constructor as function, you need to use 'new' keyword"));

    if (args[0]->IsExternal())
    {
        //std::clog << "external!\n";
        Local<External> ext = Local<External>::Cast(args[0]);
        void* ptr = ext->Value();
        Geometry* g =  static_cast<Geometry*>(ptr);
        g->Wrap(args.This());
        return args.This();
    }
    else
    {
        return ThrowException(Exception::Error(
                                  String::New("a mapnik.Geometry cannot be created directly - rather you should create mapnik.Path objects which can contain one or more geometries")));
    }
    return args.This();
}

Handle<Value> Geometry::extent(const Arguments& args)
{
    HandleScope scope;

    Geometry* g = ObjectWrap::Unwrap<Geometry>(args.This());

    Local<Array> a = Array::New(4);
    mapnik::box2d<double> const& e = g->get()->envelope();
    a->Set(0, Number::New(e.minx()));
    a->Set(1, Number::New(e.miny()));
    a->Set(2, Number::New(e.maxx()));
    a->Set(3, Number::New(e.maxy()));

    return scope.Close(a);
}

Handle<Value> Geometry::type(const Arguments& args)
{
    HandleScope scope;

    Geometry* g = ObjectWrap::Unwrap<Geometry>(args.This());

    mapnik::eGeomType type = g->get()->type();
    // TODO - can we return the actual symbol?
    //return scope.Close(constructor->GetFunction()->Get(String::NewSymbol("Point")));
    return scope.Close(Integer::New(static_cast<int>(type)));
}
<commit_msg>fix indents<commit_after>#include "utils.hpp"
#include "mapnik_geometry.hpp"

// mapnik
#include <mapnik/wkt/wkt_factory.hpp>

// boost
#include <boost/make_shared.hpp>

Persistent<FunctionTemplate> Geometry::constructor;

void Geometry::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Geometry::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Geometry"));

    NODE_SET_PROTOTYPE_METHOD(constructor, "extent", extent);
    NODE_SET_PROTOTYPE_METHOD(constructor, "type", type);
    NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                "Point",mapnik::Point)
    NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                "LineString",mapnik::LineString)
    NODE_MAPNIK_DEFINE_CONSTANT(constructor->GetFunction(),
                                "Polygon",mapnik::Polygon)
    target->Set(String::NewSymbol("Geometry"),constructor->GetFunction());
}

Geometry::Geometry() :
    ObjectWrap(),
    this_() {}

Geometry::~Geometry()
{
}

Handle<Value> Geometry::New(const Arguments& args)
{
    HandleScope scope;
    //if (!args.IsConstructCall())
    //    return ThrowException(String::New("Cannot call constructor as function, you need to use 'new' keyword"));

    if (args[0]->IsExternal())
    {
        //std::clog << "external!\n";
        Local<External> ext = Local<External>::Cast(args[0]);
        void* ptr = ext->Value();
        Geometry* g =  static_cast<Geometry*>(ptr);
        g->Wrap(args.This());
        return args.This();
    }
    else
    {
        return ThrowException(Exception::Error(
                                  String::New("a mapnik.Geometry cannot be created directly - rather you should create mapnik.Path objects which can contain one or more geometries")));
    }
    return args.This();
}

Handle<Value> Geometry::extent(const Arguments& args)
{
    HandleScope scope;

    Geometry* g = ObjectWrap::Unwrap<Geometry>(args.This());

    Local<Array> a = Array::New(4);
    mapnik::box2d<double> const& e = g->get()->envelope();
    a->Set(0, Number::New(e.minx()));
    a->Set(1, Number::New(e.miny()));
    a->Set(2, Number::New(e.maxx()));
    a->Set(3, Number::New(e.maxy()));

    return scope.Close(a);
}

Handle<Value> Geometry::type(const Arguments& args)
{
    HandleScope scope;

    Geometry* g = ObjectWrap::Unwrap<Geometry>(args.This());

    mapnik::eGeomType type = g->get()->type();
    // TODO - can we return the actual symbol?
    //return scope.Close(constructor->GetFunction()->Get(String::NewSymbol("Point")));
    return scope.Close(Integer::New(static_cast<int>(type)));
}
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <linefollowing/AlignAction.h>
#include <linefollowing/AlignActionFeedback.h>
#include <linefollowing/AlignActionResult.h>

#include <motionlibrary/ForwardAction.h>
#include <motionlibrary/ForwardActionFeedback.h>
#include <motionlibrary/ForwardActionResult.h>

#include <linedetection/orangeAction.h>
#include <linedetection/orangeActionFeedback.h>
#include <linedetection/orangeActionResult.h>

#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

using namespace std;

typedef actionlib::SimpleActionClient<linedetection::orangeAction> orange;
typedef actionlib::SimpleActionClient<linefollowing::AlignAction> Align;
typedef actionlib::SimpleActionClient<motionlibrary::ForwardAction> forward;

linedetection::orangeGoal orangegoal;
linefollowing::AlignGoal aligngoal;
motionlibrary::ForwardGoal forwardgoal;

bool orangeSuccess= false;
bool alignSuccess = false;
bool forwardSuccess = false;

void spinThread(){
	ros::spin();
}

void forwardCb(linedetection::orangeActionFeedback msg){
	ROS_INFO("feedback recieved %d",msg.feedback.nosignificance);
}
void AlignCb(linefollowing::AlignActionFeedback msg){
	ROS_INFO("feedback recieved %fsec remaining ",msg.feedback.AngleRemaining);
}

int main(int argc, char** argv){
	if(argc<2){
		cout<<"please specify the time for forward motion" << endl;
		return 0;
	}
	float forwardTime;
	forwardTime = atof(argv[1]);

	ros::init(argc, argv,"TheMasterNode" );
	ros::NodeHandle nh;
	//here linedetectionserver is the name of the node of the actionserver.
	ros::Subscriber subOrange = nh.subscribe<linedetection::orangeActionFeedback>("/linedetectionserver/feedback",1000,&forwardCb);
	ros::Subscriber subAlign = nh.subscribe<linefollowing::AlignActionFeedback>("/Align/feedback",1000,&AlignCb);

	orange orangeClient("linedetectionserver");

	Align AlignClient("Align");

	forward forwardClient("forward");

	ROS_INFO("Waiting for linedetection server to start.");
	orangeClient.waitForServer();
	ROS_INFO("linedetection server started");

	ROS_INFO("Waiting for align server to start.");
	AlignClient.waitForServer();
	ROS_INFO("Align server started.");

	boost::thread spin_thread(&spinThread);

	while(ros::ok()){
		forwardgoal.MotionTime = 2;
		forwardClient.sendGoal(forwardgoal);
		ROS_INFO("Moving forward");
		forwardClient.waitForResult();
		forwardSuccess = (*(forwardClient.getResult())).MotionCompleted;
		if(forwardSuccess){
			ROS_INFO("forward motion successful");
		}
		else
			ROS_INFO("forward motion unsuccessful");

		orangegoal.order = true;
		orangeClient.sendGoal(orangegoal);
		ROS_INFO("Orange detection started");
		orangeClient.waitForResult();
		orangeSuccess = (*(orangeClient.getResult())).MotionCompleted;
		if(orangeSuccess){
			ROS_INFO("orange colour detected");
		}
		else
			ROS_INFO("orange not detected");

		aligngoal.StartDetection = true;
		AlignClient.sendGoal(aligngoal);
		ROS_INFO("Alignment started");
		AlignClient.waitForResult();
		alignSuccess = (*(orangeClient.getResult())).MotionCompleted;
		if(alignSuccess){
			ROS_INFO("alignment successful");
		}
		else
			ROS_INFO("alignment failed");
	}
	return 0;
}<commit_msg>moved forward motion below<commit_after>#include <ros/ros.h>
#include <linefollowing/AlignAction.h>
#include <linefollowing/AlignActionFeedback.h>
#include <linefollowing/AlignActionResult.h>

#include <motionlibrary/ForwardAction.h>
#include <motionlibrary/ForwardActionFeedback.h>
#include <motionlibrary/ForwardActionResult.h>

#include <linedetection/orangeAction.h>
#include <linedetection/orangeActionFeedback.h>
#include <linedetection/orangeActionResult.h>

#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>

using namespace std;

typedef actionlib::SimpleActionClient<linedetection::orangeAction> orange;
typedef actionlib::SimpleActionClient<linefollowing::AlignAction> Align;
typedef actionlib::SimpleActionClient<motionlibrary::ForwardAction> forward;

linedetection::orangeGoal orangegoal;
linefollowing::AlignGoal aligngoal;
motionlibrary::ForwardGoal forwardgoal;

bool orangeSuccess= false;
bool alignSuccess = false;
bool forwardSuccess = false;

void spinThread(){
	ros::spin();
}

void forwardCb(linedetection::orangeActionFeedback msg){
	ROS_INFO("feedback recieved %d",msg.feedback.nosignificance);
}
void AlignCb(linefollowing::AlignActionFeedback msg){
	ROS_INFO("feedback recieved %fsec remaining ",msg.feedback.AngleRemaining);
}

int main(int argc, char** argv){
	if(argc<2){
		cout<<"please specify the time for forward motion" << endl;
		return 0;
	}
	float forwardTime;
	forwardTime = atof(argv[1]);

	ros::init(argc, argv,"TheMasterNode" );
	ros::NodeHandle nh;
	//here linedetectionserver is the name of the node of the actionserver.
	ros::Subscriber subOrange = nh.subscribe<linedetection::orangeActionFeedback>("/linedetectionserver/feedback",1000,&forwardCb);
	ros::Subscriber subAlign = nh.subscribe<linefollowing::AlignActionFeedback>("/Align/feedback",1000,&AlignCb);

	orange orangeClient("linedetectionserver");

	Align AlignClient("Align");

	forward forwardClient("forward");

	ROS_INFO("Waiting for linedetection server to start.");
	orangeClient.waitForServer();
	ROS_INFO("linedetection server started");

	ROS_INFO("Waiting for align server to start.");
	AlignClient.waitForServer();
	ROS_INFO("Align server started.");

	boost::thread spin_thread(&spinThread);

	while(ros::ok()){
		orangegoal.order = true;
		orangeClient.sendGoal(orangegoal);
		ROS_INFO("Orange detection started");
		orangeClient.waitForResult();
		orangeSuccess = (*(orangeClient.getResult())).MotionCompleted;
		if(orangeSuccess){
			ROS_INFO("orange colour detected");
		}
		else
			ROS_INFO("orange not detected");

		aligngoal.StartDetection = true;
		AlignClient.sendGoal(aligngoal);
		ROS_INFO("Alignment started");
		AlignClient.waitForResult();
		alignSuccess = (*(orangeClient.getResult())).MotionCompleted;
		if(alignSuccess){
			ROS_INFO("alignment successful");
		}
		else
			ROS_INFO("alignment failed");
		forwardgoal.MotionTime = forwardTime;
		forwardClient.sendGoal(forwardgoal);
		ROS_INFO("Moving forward");
		forwardClient.waitForResult();
		forwardSuccess = (*(forwardClient.getResult())).MotionCompleted;
		if(forwardSuccess){
			ROS_INFO("forward motion successful");
		}
		else
			ROS_INFO("forward motion unsuccessful");

	}
	return 0;
}<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
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 author 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 OWNER OR CONTRIBUTORS 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.

*/

#include <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>

int test_main();

extern bool tests_failure;

int main()
{
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif
	fflush(stdout);
	fflush(stderr);
	return tests_failure ? 1 : 0;
}

<commit_msg>make tests catch fatal signals and present a nice stack for the error<commit_after>/*

Copyright (c) 2008, Arvid Norberg
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 author 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 OWNER OR CONTRIBUTORS 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.

*/

#include <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>

int test_main();

extern bool tests_failure;

#include "libtorrent/assert.hpp"
#include <signal.h>

void sig_handler(int sig)
{
	char stack_text[10000];
	print_backtrace(stack_text, sizeof(stack_text), 30);
	char const* sig_name = 0;
	switch (sig)
	{
#define SIG(x) case x: sig_name = #x; break
		SIG(SIGSEGV);
		SIG(SIGBUS);
		SIG(SIGILL);
		SIG(SIGABRT);
		SIG(SIGFPE);
		SIG(SIGSYS);
#undef SIG
	};
	fprintf(stderr, "signal: %s caught:\n%s\n", sig_name, stack_text);
	exit(138);
}

int main()
{
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

	signal(SIGSEGV, &sig_handler);
	signal(SIGBUS, &sig_handler);
	signal(SIGILL, &sig_handler);
	signal(SIGABRT, &sig_handler);
	signal(SIGFPE, &sig_handler);
	signal(SIGSYS, &sig_handler);

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif
	fflush(stdout);
	fflush(stderr);
	return tests_failure ? 1 : 0;
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief Main code block.
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-10-27
 */

#include "testThreadFunction.hpp"

#include "distortos/StaticThread.hpp"

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {10240};

/// test thread
auto testThread = distortos::makeStaticThread<testThreadStackSize>(UINT8_MAX / 2, distortos::test::testThreadFunction);

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief main code block
 */

int main()
{
	testThread.start();
	testThread.join();

	return 0;
}
<commit_msg>main: use bigger stack for test thread if _REENT_SMALL is _NOT_ defined<commit_after>/**
 * \file
 * \brief Main code block.
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-07
 */

#include "testThreadFunction.hpp"

#include "distortos/StaticThread.hpp"

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local objects
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
#ifdef _REENT_SMALL
constexpr size_t testThreadStackSize {10240};
#else
constexpr size_t testThreadStackSize {20480};
#endif	// def _REENT_SMALL

/// test thread
auto testThread = distortos::makeStaticThread<testThreadStackSize>(UINT8_MAX / 2, distortos::test::testThreadFunction);

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief main code block
 */

int main()
{
	testThread.start();
	testThread.join();

	return 0;
}
<|endoftext|>