<commit_before>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2013, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is 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.
// __END_LICENSE__

/// \file gen_pcd.cc.
/// Create a .pcd file and apply a transform to it. This is an undocumented
/// low-level utility which is still not fully developed and hooked
/// up to other functionality.

// TODO(oalexan1): Clean up these header files
#include <asp/Core/PointUtils.h>
#include <asp/Core/Macros.h>
#include <asp/Core/Common.h>
#include <asp/Core/StereoSettings.h>

#include <vw/Core/Stopwatch.h>
#include <vw/Core/StringUtils.h>
#include <vw/Cartography/GeoReferenceUtils.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/FileIO/DiskImageUtils.h>
#include <vw/InterestPoint/MatrixIO.h>

#include <pcl/io/pcd_io.h>

#include <limits>

using namespace vw;
using namespace vw::cartography;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

struct Options : vw::cartography::GdalWriteOptions {
  // Input
  std::vector<std::string> files;

  // Defaults that the user doesn't need to see.
  Options() {}
};

void handle_arguments( int argc, char *argv[], Options& opt ) {

  po::options_description general_options("General options");
  //general_options.add_options()

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value< std::vector<std::string> >(), "Input files");

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  std::string usage("[options] <point-clouds> [ --orthoimage <textures> ]");
  bool allow_unregistered = false;
  std::vector<std::string> unregistered;
  po::variables_map vm =
    asp::check_command_line(argc, argv, opt, general_options, general_options,
                             positional, positional_desc, usage,
                             allow_unregistered, unregistered);

  if (vm.count("input-files") == 0)
    vw_throw( ArgumentErr() << "Missing input point clouds.\n" << usage << general_options );
  opt.files = vm["input-files"].as< std::vector<std::string> >();

}

int main( int argc, char *argv[] ) {
  Options opt;
  try {
    handle_arguments(argc, argv, opt);

    // Read the point cloud fully in memory, and remove any offset
    std::string cloud_file = opt.files[0];
    ImageViewRef<Vector3> point_image = asp::read_asp_point_cloud<3>(cloud_file);
    std::cout << "Read point cloud: " << cloud_file << std::endl;

    std::string texture_file = opt.files[1];
    ImageView<float> texture = DiskImageView<float>(texture_file);
    std::cout << "Read texture file: " << texture_file << std::endl;
    bool has_nodata = false;
    float texture_nodata = -32768.0;
    if (vw::read_nodata_val(texture_file, texture_nodata)) {
      has_nodata = true;
      std::cout << "Read texture nodata value: " << texture_nodata << std::endl;
    }

    if (point_image.cols() != texture.cols() || point_image.rows() != texture.rows())
    vw_throw( ArgumentErr() << "The input point cloud and texture must have the same dimensions.");

    vw::Matrix<double> cam2world;
    std::string trans_file = opt.files[2];
    vw_out() << "Reading the alignment transform from: " << trans_file << "\n";
    vw::read_matrix_as_txt(trans_file, cam2world);
    std::cout << "Read transform " << cam2world << std::endl;
    vw::Matrix<double> world2cam = inverse(cam2world);

    std::string pcd_file = opt.files[3];

    double inf = std::numeric_limits<double>::infinity();
    pcl::PointCloud<pcl::PointNormal> pci;
    pci.width = point_image.cols();
    pci.height = point_image.rows();
    pci.points.resize(pci.width * pci.height);

    int count = -1;
    for (int col = 0; col < point_image.cols(); col++) {
      for (int row = 0; row < point_image.rows(); row++) {
        count++;

        Vector3 P = point_image(col, row);

        if (P == Vector3() || texture(col, row) == texture_nodata) {
          // This is needed for VoxBlox.
          pci.points[count].x = inf;
          pci.points[count].y = inf;
          pci.points[count].z = inf;
          pci.points[count].normal_x  = 0;  // intensity
          pci.points[count].normal_y  = 0;  // weight
          pci.points[count].normal_z  = 0;  // ensure initialization
          pci.points[count].curvature = 0;  // ensure initialization
          continue;
        }

        // Create homogeneous coordinates
        Vector<double, 4> Q;
        subvector(Q, 0, 3) = P;
        Q[3] = 1;

        // Convert to camera's coordinate system, as expected by voxblox
        Q = world2cam * Q;

        pci.points[count].x = Q[0];
        pci.points[count].y = Q[1];
        pci.points[count].z = Q[2];

        // The input texture is usually between 0 and 1.
        // TODO(oalexan1): What is the max color?
        double t = 255.0 * texture(col, row);
        if (t <= 0.0) t = 1.0;  // Ensure a positive value for the color

        // All points are given equal weight for now
        double wt = 1.0;

        pci.points[count].normal_x = t;   // intensity
        pci.points[count].normal_y = wt;  // weight
        pci.points[count].normal_z  = 0;  // ensure initialization to something
        pci.points[count].curvature = 0;
      }
    }

    std::cout << "Writing: " << pcd_file << std::endl;
    pcl::io::savePCDFileASCII(pcd_file, pci);

    return 0;

  } ASP_STANDARD_CATCHES;

  return 0;
}
<commit_msg>Implement some filtering options<commit_after>// __BEGIN_LICENSE__
//  Copyright (c) 2009-2013, United States Government as represented by the
//  Administrator of the National Aeronautics and Space Administration. All
//  rights reserved.
//
//  The NGT platform is 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.
// __END_LICENSE__

/// \file gen_pcd.cc.
/// Create a .pcd file and apply a transform to it. This is an undocumented
/// low-level utility which is still not fully developed and hooked
/// up to other functionality.

// TODO(oalexan1): Clean up these header files
#include <asp/Core/PointUtils.h>
#include <asp/Core/Macros.h>
#include <asp/Core/Common.h>
#include <asp/Core/StereoSettings.h>

#include <vw/Core/Stopwatch.h>
#include <vw/Core/StringUtils.h>
#include <vw/Cartography/GeoReferenceUtils.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/FileIO/DiskImageUtils.h>
#include <vw/InterestPoint/MatrixIO.h>

#include <pcl/io/pcd_io.h>
#include <Eigen/Core>
#include <Eigen/SVD>

#include <limits>

using namespace vw;
using namespace vw::cartography;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

struct Options : vw::cartography::GdalWriteOptions {
  // Input
  std::vector<std::string> files;
  Vector2     remove_outliers_params;
  double      max_valid_triangulation_error, distance_from_camera_weight_power,
    max_camera_ray_to_surface_normal_angle, max_camera_dir_to_camera_ray_angle;

  // Defaults that the user doesn't need to see.
  Options() {}
};

// TODO(oalexan1): Move this to utils and do not include any Eigen header.
// Eigen, PCL, and VW combined make compilation impossibly long.
// Find the best fitting plane to a set of points.
void bestFitPlane(const std::vector<Eigen::Vector3d>& points, Eigen::Vector3d& centroid,
                  Eigen::Vector3d& plane_normal) {
  // Copy coordinates to  matrix in Eigen format
  size_t num_points = points.size();
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> coord(3, num_points);

  for (size_t i = 0; i < num_points; i++) coord.col(i) = points[i];

  // calculate centroid
  centroid = Eigen::Vector3d(coord.row(0).mean(), coord.row(1).mean(), coord.row(2).mean());

  // subtract centroid
  for (size_t it = 0; it < 3; it++) coord.row(it).array() -= centroid(it);

  // We only need the left-singular matrix here
  // https://math.stackexchange.com/questions/99299/best-fitting-plane-given-a-set-of-points
  auto svd = coord.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);

  plane_normal = svd.matrixU().rightCols<1>();
}

void handle_arguments( int argc, char *argv[], Options& opt ) {

  po::options_description general_options("General options");
  general_options.add_options()
    ("remove-outliers-params",        po::value(&opt.remove_outliers_params)->default_value(Vector2(75.0, 3.0), "pct factor"),
            "Outlier removal based on percentage. Points with triangulation error larger than pct-th percentile times factor and points too far from the cluster of most points will be removed as outliers. [default: pct=75.0, factor=3.0]")
    ("max-valid-triangulation-error", po::value(&opt.max_valid_triangulation_error)->default_value(0),
     "Outlier removal based on threshold. If positive, points with triangulation error larger than this will be removed from the cloud. Measured in meters. This option takes precedence over --remove-outliers-params.")
    ("distance-from-camera-weight-power", po::value(&opt.distance_from_camera_weight_power)->default_value(0),
     "If positive, let the weight of a 3D point be inversely proportional to the distance from the camera center to the point, raised to this power.")

    ("max-camera-ray-to-surface-normal-angle", po::value(&opt.max_camera_ray_to_surface_normal_angle)->default_value(0),
     "If positive, surface points whose surface normal makes an angle with the ray back to the camera center greater than this will be removed as an outlier.")
      ("max-camera-dir-to-camera-ray-angle", po::value(&opt.max_camera_dir_to_camera_ray_angle)->default_value(0),
     "If positive, and a ray emanating from the camera and ending at the current point makes an angle with the camera direction bigger than this, remove the point as an outlier. In effect, this narrows the camera field of view.");

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value< std::vector<std::string> >(), "Input files");

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  std::string usage("[options] <point-clouds> [ --orthoimage <textures> ]");
  bool allow_unregistered = false;
  std::vector<std::string> unregistered;
  po::variables_map vm =
    asp::check_command_line(argc, argv, opt, general_options, general_options,
                             positional, positional_desc, usage,
                             allow_unregistered, unregistered);

  if (vm.count("input-files") == 0)
    vw_throw( ArgumentErr() << "Missing input point clouds.\n" << usage << general_options );
  opt.files = vm["input-files"].as< std::vector<std::string> >();

}

int main( int argc, char *argv[] ) {
  Options opt;
  try {
    handle_arguments(argc, argv, opt);

    std::cout << "--max valid tri error " << opt.max_valid_triangulation_error << std::endl;

    // For now only 4 channels are supported
    // TODO(oalexan1): Support also 3 channels
    int num_channels = get_num_channels(opt.files[0]);
    if (num_channels != 4)
      vw_throw( ArgumentErr() << "The input point cloud must have 4 channels.");

    // Read the point cloud fully in memory, and remove any offset
    std::string cloud_file = opt.files[0];
    ImageViewRef<Vector<double, 4>> point_image = asp::read_asp_point_cloud<4>(cloud_file);
    std::cout << "Read point cloud: " << cloud_file << std::endl;

    std::string texture_file = opt.files[1];
    ImageView<float> texture = DiskImageView<float>(texture_file);
    std::cout << "Read texture file: " << texture_file << std::endl;
    bool has_nodata = false;
    float texture_nodata = -32768.0;
    if (vw::read_nodata_val(texture_file, texture_nodata)) {
      has_nodata = true;
      std::cout << "Read texture nodata value: " << texture_nodata << std::endl;
    }

    if (point_image.cols() != texture.cols() || point_image.rows() != texture.rows())
    vw_throw( ArgumentErr() << "The input point cloud and texture must have the same dimensions.");

    vw::Matrix<double> cam2world;
    std::string trans_file = opt.files[2];
    vw_out() << "Reading the alignment transform from: " << trans_file << "\n";
    vw::read_matrix_as_txt(trans_file, cam2world);
    std::cout << "Read transform " << cam2world << std::endl;
    vw::Matrix<double> world2cam = inverse(cam2world);

    std::string pcd_file = opt.files[3];

    double inf = std::numeric_limits<double>::infinity();
    pcl::PointCloud<pcl::PointNormal> pci;
    pci.width = point_image.cols();
    pci.height = point_image.rows();
    pci.points.resize(pci.width * pci.height);

    double max_err = opt.max_valid_triangulation_error;
    int count = -1;
    for (int col = 0; col < point_image.cols(); col++) {
      for (int row = 0; row < point_image.rows(); row++) {
        count++;

        // An output point starts by default as an outlier
        // Make it inf, as VoxBlox expects.
        pci.points[count].x         = inf;
        pci.points[count].y         = inf;
        pci.points[count].z         = inf;
        pci.points[count].normal_x  = 0;  // intensity
        pci.points[count].normal_y  = 0;  // weight
        pci.points[count].normal_z  = 0;  // ensure initialization
        pci.points[count].curvature = 0;  // ensure initialization

        Vector<double, 4> P = point_image(col, row);

        if (P == Vector<double, 4>() || texture(col, row) == texture_nodata ||
            (max_err > 0 && P[3] > max_err)) {
          continue; // outlier
        }

        // Create homogeneous coordinates
        Vector<double, 4> Q;
        subvector(Q, 0, 3) = subvector(P, 0, 3);
        Q[3] = 1;

        // Convert to camera's coordinate system, as expected by voxblox
        Q = world2cam * Q;

        // All points are given equal weight for now
        double wt = 1.0;
        if (opt.distance_from_camera_weight_power > 0) {
          double dist = norm_2(subvector(Q, 0, 3));
          if (dist == 0.0)
            continue; // outlier

          wt = 1.0 / pow(dist, opt.distance_from_camera_weight_power);
        }

        if (opt.max_camera_ray_to_surface_normal_angle > 0) {
          // See the angle between camera ray and surface normal
          std::vector<Eigen::Vector3d> near_points;
          for (int c = col - 1; c <= col + 1; c++) {
            for (int r = row - 1; r <= row + 1; r++) {
              if (c < 0 || c >= point_image.cols())
                continue;
              if (r < 0 || r >= point_image.rows())
                continue;

              // TODO(oalexan1): Too much code repetition here
              Vector<double, 4> P0 = point_image(c, r);
              if (P0 == Vector<double, 4>())
                continue; // outlier
              // Create homogeneous coordinates
              Vector<double, 4> Q0;
              subvector(Q0, 0, 3) = subvector(P0, 0, 3);
              Q0[3] = 1;
              // Convert to camera's coordinate system, as expected by voxblox
              Q0 = world2cam * Q0;

              near_points.push_back(Eigen::Vector3d(Q0[0], Q0[1], Q0[2]));
            }
          }

          if (near_points.size() < 5)
            continue; // outlier
          Eigen::Vector3d plane_normal, centroid;
          bestFitPlane(near_points, centroid, plane_normal);

          Vector3 N(plane_normal[0], plane_normal[1], plane_normal[2]);
          // Use abs as the normal can point in either direction
          double prod = std::abs(dot_prod(Q, N)/ norm_2(Q) / norm_2(N));

          double angle = acos(prod) * (180.0 / M_PI);
          if (std::isnan(angle) || std::isinf(angle))
            continue; // something went wrong

          // std::cout << "--angle is " << angle << std::endl;

          if (angle > opt.max_camera_ray_to_surface_normal_angle)
            continue; // outlier
        }

        if (opt.max_camera_dir_to_camera_ray_angle > 0) {
          Vector3 cam_dir(0.0, 0.0, 1.0);

          double prod = std::abs(dot_prod(Q, cam_dir)/ norm_2(Q) / norm_2(cam_dir));

          double angle = acos(prod) * (180.0 / M_PI);
          if (std::isnan(angle) || std::isinf(angle))
            continue; // something went wrong

          if (angle > opt.max_camera_dir_to_camera_ray_angle)
            continue; // outlier
        }

        // The input texture is usually between 0 and 1.
        // TODO(oalexan1): What is the max color?
        double t = 255.0 * texture(col, row);
        if (t <= 0.0) t = 1.0;  // Ensure a positive value for the color

        pci.points[count].x         = Q[0];
        pci.points[count].y         = Q[1];
        pci.points[count].z         = Q[2];
        pci.points[count].normal_x  = t;   // intensity
        pci.points[count].normal_y  = wt;  // weight
        pci.points[count].normal_z  = 0;  // ensure initialization to something
        pci.points[count].curvature = 0;
      }
    }

    // Create the output directory

    vw::create_out_dir(pcd_file);
    std::cout << "Writing: " << pcd_file << std::endl;
    pcl::io::savePCDFileASCII(pcd_file, pci);

    return 0;

  } ASP_STANDARD_CATCHES;

  return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>

#include "ast/DebugVisitor.hpp"
#include "ast/SourceFile.hpp"

#include "VisitorUtils.hpp"
#include "Variable.hpp"

using namespace eddic;

ast::DebugVisitor::DebugVisitor() : level(0) {}

std::string ast::DebugVisitor::indent() const {
    std::string acc = "";
    for(int i = 0; i < level; ++i){
        acc += "\t";
    }
    return acc;
}

std::string toStringType(ast::Type type){
    if(auto* ptr = boost::get<ast::SimpleType>(&type)){
        return ptr->type;
    } else if(auto* ptr = boost::get<ast::ArrayType>(&type)){
        return ptr->type + "[]";
    }

    ASSERT_PATH_NOT_TAKEN("The given type is not an AST Type");
}

void ast::DebugVisitor::operator()(ast::SourceFile& program) const {
    std::cout << indent() << "SourceFile" << std::endl;

    ++level;

    visit_each(*this, program.Content->blocks);
}

void ast::DebugVisitor::operator()(ast::Import& import) const {
    std::cout << indent() << "include \"" << import.file << "\"" << std::endl;
}

void ast::DebugVisitor::operator()(ast::StandardImport& import) const {
    std::cout << indent() << "include <" << import.header << ">" << std::endl;
}

template<typename Visitor, typename Container>
void print_each_sub(Visitor& visitor, Container& container){
    visitor.level++;
    visit_each(visitor, container);
    visitor.level--;
}

template<typename Visitor, typename Container>
void print_sub(Visitor& visitor, Container& container){
    visitor.level++;
    visit(visitor, container);
    visitor.level--;
}

void ast::DebugVisitor::operator()(ast::FunctionDeclaration& declaration) const {
    std::cout << indent() << "Function " << declaration.Content->functionName << std::endl;
    print_each_sub(*this, declaration.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::GlobalVariableDeclaration&) const {
    std::cout << indent() << "Global Variable" << std::endl;
}

void ast::DebugVisitor::operator()(ast::GlobalArrayDeclaration&) const {
    std::cout << indent() << "Global Array" << std::endl;
}

void ast::DebugVisitor::operator()(ast::For& for_) const {
    std::cout << indent() << "For" << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::Foreach& for_) const {
    std::cout << indent() << "Foreach" << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::ForeachIn& for_) const {
    std::cout << indent() << "Foreach in " << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::While& while_) const {
    std::cout << indent() << "While" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, while_.Content->condition);
    print_each_sub(*this, while_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::DoWhile& while_) const {
    std::cout << indent() << "Do while" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, while_.Content->condition);
    print_each_sub(*this, while_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::Swap&) const {
    std::cout << indent() << "Swap" << std::endl;
}

void ast::DebugVisitor::operator()(ast::If& if_) const {
    std::cout << indent() << "If" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, if_.Content->condition);
    std::cout << indent() << "Body:" << std::endl;
    print_each_sub(*this, if_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::FunctionCall& call) const {
    std::cout << indent() << "FunctionCall " << call.Content->functionName << std::endl;
    print_each_sub(*this, call.Content->values);
}

void ast::DebugVisitor::operator()(ast::BuiltinOperator& builtin) const {
    std::cout << indent() << "Builtin Operator " << (int) builtin.Content->type << std::endl;
    print_each_sub(*this, builtin.Content->values);
}

void ast::DebugVisitor::operator()(ast::VariableDeclaration& declaration) const {
    std::cout << indent() << "Variable declaration" << std::endl;

    if(declaration.Content->value){
        print_sub(*this, *declaration.Content->value);
    }
}

void ast::DebugVisitor::operator()(ast::ArrayDeclaration&) const {
    std::cout << indent() << "Array declaration" << std::endl;
}

void ast::DebugVisitor::operator()(ast::SuffixOperation& op) const {
    std::cout << indent() << op.Content->variableName << "(suffix)" << (int)op.Content->op << std::endl;
}

void ast::DebugVisitor::operator()(ast::PrefixOperation& op) const {
    std::cout << indent() << (int)op.Content->op << "(prefix)" << op.Content->variableName << std::endl;
}

void ast::DebugVisitor::operator()(ast::Assignment& assign) const {
    std::cout << indent() << "Variable assignment" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::CompoundAssignment& assign) const {
    std::cout << indent() << "Compound variable assignment [operator = " << (int) assign.Content->op << " ]" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::Return& return_) const {
    std::cout << indent() << "Function return" << std::endl;
    print_sub(*this, return_.Content->value);
}

void ast::DebugVisitor::operator()(ast::ArrayAssignment& assign) const {
    std::cout << indent() << "Array assignment" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::Litteral& litteral) const {
    std::cout << indent() << "Litteral [" << litteral.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Integer& integer) const {
    std::cout << indent() << "Integer [" << integer.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::IntegerSuffix& integer) const {
    std::cout << indent() << "Float (suffix) [" << integer.value << "f]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Float& float_) const {
    std::cout << indent() << "Float [" << float_.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::True&) const {
    std::cout << indent() << "true" << std::endl;
}

void ast::DebugVisitor::operator()(ast::False&) const {
    std::cout << indent() << "false" << std::endl;
}

void ast::DebugVisitor::operator()(ast::VariableValue& value) const {
    std::cout << indent() << "Variable [" << value.Content->var->name()  << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::ArrayValue&) const {
    std::cout << indent() << "Array value" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Expression& value) const {
    std::cout << indent() << "Expression [" << value.Content->operations.size() << "]" << std::endl;
    ++level;
    visit(*this, value.Content->first);
    for(auto& operation : value.Content->operations){
        std::cout << indent() << (int) operation.get<0>() << std::endl;
        visit(*this, operation.get<1>());
    }
    --level;
}

void ast::DebugVisitor::operator()(ast::Minus& value) const {
    std::cout << indent() << "Unary +" << std::endl;
    print_sub(*this, value.Content->value);
}

void ast::DebugVisitor::operator()(ast::Plus& value) const {
    std::cout << indent() << "Unary -" << std::endl;
    print_sub(*this, value.Content->value);
}

void ast::DebugVisitor::operator()(ast::Cast& cast) const {
    std::cout << indent() << "Cast " << std::endl;
    std::cout << indent() << "\tType: " << toStringType(cast.Content->type) << std::endl;
    print_sub(*this, cast.Content->value);
}
<commit_msg>Add forgotten include<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>

#include "ast/DebugVisitor.hpp"
#include "ast/SourceFile.hpp"

#include "assert.hpp"
#include "VisitorUtils.hpp"
#include "Variable.hpp"

using namespace eddic;

ast::DebugVisitor::DebugVisitor() : level(0) {}

std::string ast::DebugVisitor::indent() const {
    std::string acc = "";
    for(int i = 0; i < level; ++i){
        acc += "\t";
    }
    return acc;
}

std::string toStringType(ast::Type type){
    if(auto* ptr = boost::get<ast::SimpleType>(&type)){
        return ptr->type;
    } else if(auto* ptr = boost::get<ast::ArrayType>(&type)){
        return ptr->type + "[]";
    }

    ASSERT_PATH_NOT_TAKEN("The given type is not an AST Type");
}

void ast::DebugVisitor::operator()(ast::SourceFile& program) const {
    std::cout << indent() << "SourceFile" << std::endl;

    ++level;

    visit_each(*this, program.Content->blocks);
}

void ast::DebugVisitor::operator()(ast::Import& import) const {
    std::cout << indent() << "include \"" << import.file << "\"" << std::endl;
}

void ast::DebugVisitor::operator()(ast::StandardImport& import) const {
    std::cout << indent() << "include <" << import.header << ">" << std::endl;
}

template<typename Visitor, typename Container>
void print_each_sub(Visitor& visitor, Container& container){
    visitor.level++;
    visit_each(visitor, container);
    visitor.level--;
}

template<typename Visitor, typename Container>
void print_sub(Visitor& visitor, Container& container){
    visitor.level++;
    visit(visitor, container);
    visitor.level--;
}

void ast::DebugVisitor::operator()(ast::FunctionDeclaration& declaration) const {
    std::cout << indent() << "Function " << declaration.Content->functionName << std::endl;
    print_each_sub(*this, declaration.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::GlobalVariableDeclaration&) const {
    std::cout << indent() << "Global Variable" << std::endl;
}

void ast::DebugVisitor::operator()(ast::GlobalArrayDeclaration&) const {
    std::cout << indent() << "Global Array" << std::endl;
}

void ast::DebugVisitor::operator()(ast::For& for_) const {
    std::cout << indent() << "For" << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::Foreach& for_) const {
    std::cout << indent() << "Foreach" << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::ForeachIn& for_) const {
    std::cout << indent() << "Foreach in " << std::endl;
    print_each_sub(*this, for_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::While& while_) const {
    std::cout << indent() << "While" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, while_.Content->condition);
    print_each_sub(*this, while_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::DoWhile& while_) const {
    std::cout << indent() << "Do while" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, while_.Content->condition);
    print_each_sub(*this, while_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::Swap&) const {
    std::cout << indent() << "Swap" << std::endl;
}

void ast::DebugVisitor::operator()(ast::If& if_) const {
    std::cout << indent() << "If" << std::endl;
    std::cout << indent() << "Condition:" << std::endl;
    print_sub(*this, if_.Content->condition);
    std::cout << indent() << "Body:" << std::endl;
    print_each_sub(*this, if_.Content->instructions);
}

void ast::DebugVisitor::operator()(ast::FunctionCall& call) const {
    std::cout << indent() << "FunctionCall " << call.Content->functionName << std::endl;
    print_each_sub(*this, call.Content->values);
}

void ast::DebugVisitor::operator()(ast::BuiltinOperator& builtin) const {
    std::cout << indent() << "Builtin Operator " << (int) builtin.Content->type << std::endl;
    print_each_sub(*this, builtin.Content->values);
}

void ast::DebugVisitor::operator()(ast::VariableDeclaration& declaration) const {
    std::cout << indent() << "Variable declaration" << std::endl;

    if(declaration.Content->value){
        print_sub(*this, *declaration.Content->value);
    }
}

void ast::DebugVisitor::operator()(ast::ArrayDeclaration&) const {
    std::cout << indent() << "Array declaration" << std::endl;
}

void ast::DebugVisitor::operator()(ast::SuffixOperation& op) const {
    std::cout << indent() << op.Content->variableName << "(suffix)" << (int)op.Content->op << std::endl;
}

void ast::DebugVisitor::operator()(ast::PrefixOperation& op) const {
    std::cout << indent() << (int)op.Content->op << "(prefix)" << op.Content->variableName << std::endl;
}

void ast::DebugVisitor::operator()(ast::Assignment& assign) const {
    std::cout << indent() << "Variable assignment" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::CompoundAssignment& assign) const {
    std::cout << indent() << "Compound variable assignment [operator = " << (int) assign.Content->op << " ]" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::Return& return_) const {
    std::cout << indent() << "Function return" << std::endl;
    print_sub(*this, return_.Content->value);
}

void ast::DebugVisitor::operator()(ast::ArrayAssignment& assign) const {
    std::cout << indent() << "Array assignment" << std::endl;
    print_sub(*this, assign.Content->value);
}

void ast::DebugVisitor::operator()(ast::Litteral& litteral) const {
    std::cout << indent() << "Litteral [" << litteral.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Integer& integer) const {
    std::cout << indent() << "Integer [" << integer.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::IntegerSuffix& integer) const {
    std::cout << indent() << "Float (suffix) [" << integer.value << "f]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Float& float_) const {
    std::cout << indent() << "Float [" << float_.value << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::True&) const {
    std::cout << indent() << "true" << std::endl;
}

void ast::DebugVisitor::operator()(ast::False&) const {
    std::cout << indent() << "false" << std::endl;
}

void ast::DebugVisitor::operator()(ast::VariableValue& value) const {
    std::cout << indent() << "Variable [" << value.Content->var->name()  << "]" << std::endl;
}

void ast::DebugVisitor::operator()(ast::ArrayValue&) const {
    std::cout << indent() << "Array value" << std::endl;
}

void ast::DebugVisitor::operator()(ast::Expression& value) const {
    std::cout << indent() << "Expression [" << value.Content->operations.size() << "]" << std::endl;
    ++level;
    visit(*this, value.Content->first);
    for(auto& operation : value.Content->operations){
        std::cout << indent() << (int) operation.get<0>() << std::endl;
        visit(*this, operation.get<1>());
    }
    --level;
}

void ast::DebugVisitor::operator()(ast::Minus& value) const {
    std::cout << indent() << "Unary +" << std::endl;
    print_sub(*this, value.Content->value);
}

void ast::DebugVisitor::operator()(ast::Plus& value) const {
    std::cout << indent() << "Unary -" << std::endl;
    print_sub(*this, value.Content->value);
}

void ast::DebugVisitor::operator()(ast::Cast& cast) const {
    std::cout << indent() << "Cast " << std::endl;
    std::cout << indent() << "\tType: " << toStringType(cast.Content->type) << std::endl;
    print_sub(*this, cast.Content->value);
}
<|endoftext|>


<commit_before>//
//  CRTC6845.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef CRTC6845_hpp
#define CRTC6845_hpp

#include "../../ClockReceiver/ClockReceiver.hpp"

#include <cstdint>
#include <cstdio>

namespace Motorola {
namespace CRTC {

struct BusState {
	bool display_enable;
	bool hsync;
	bool vsync;
	bool cursor;
	uint16_t refresh_address;
	uint16_t row_address;
};

class BusHandler {
	public:
		/*!
			Performs the first phase of a 6845 bus cycle; this is the phase in which it is intended that
			systems using the 6845 respect the bus state and produce pixels, sync or whatever they require.
		*/
		void perform_bus_cycle_phase1(const BusState &) {}

		/*!
			Performs the second phase of a 6845 bus cycle. Some bus state — including sync — is updated
			directly after phase 1 and hence is visible to an observer during phase 2. Handlers may therefore
			implement @c perform_bus_cycle_phase2 to be notified of the availability of that state without
			having to wait until the next cycle has begun.
		*/
		void perform_bus_cycle_phase2(const BusState &) {}
};

enum Personality {
	HD6845S,	//
	UM6845R,	//
	MC6845,		//
	AMS40226	//
};

template <class T> class CRTC6845 {
	public:

		CRTC6845(Personality p, T &bus_handler) noexcept :
			personality_(p), bus_handler_(bus_handler) {}

		void select_register(uint8_t r) {
			selected_register_ = r;
		}

		uint8_t get_status() const {
			return 0xff;
		}

		uint8_t get_register() const {
			if(selected_register_ < 12 || selected_register_ > 17) return 0xff;
			return registers_[selected_register_];
		}

		void set_register(uint8_t value) {
			static uint8_t masks[] = {
				0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f,
				0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff
			};

			if(selected_register_ < 16)
				registers_[selected_register_] = value & masks[selected_register_];
		}

		void trigger_light_pen() {
			registers_[17] = bus_state_.refresh_address & 0xff;
			registers_[16] = bus_state_.refresh_address >> 8;
		}

		void run_for(Cycles cycles) {
			int cyles_remaining = cycles.as_int();
			while(cyles_remaining--) {
				// check for end of horizontal sync
				if(bus_state_.hsync) {
					hsync_counter_ = (hsync_counter_ + 1) & 15;
					bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
				}

				// check for start of horizontal sync
				if(character_counter_ == registers_[2]) {
					hsync_counter_ = 0;
					if(registers_[3] & 15) bus_state_.hsync = true;
				}

				// check for end of visible characters
				if(character_counter_ == registers_[1]) {
					// TODO: consider skew in character_is_visible_. Or maybe defer until perform_bus_cycle?
					character_is_visible_ = false;
					end_of_line_address_ = bus_state_.refresh_address;
				}

				perform_bus_cycle_phase1();
				bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff;

				// check for end-of-line
				if(character_counter_ == registers_[0]) {
					character_counter_ = 0;
					do_end_of_line();
					character_is_visible_ = true;
				} else {
					// increment counter
					character_counter_++;
				}

				perform_bus_cycle_phase2();
			}
		}

		const BusState &get_bus_state() const {
			return bus_state_;
		}

	private:
		inline void perform_bus_cycle_phase1() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase1(bus_state_);
		}

		inline void perform_bus_cycle_phase2() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase2(bus_state_);
		}

		inline void do_end_of_line() {
			// check for end of vertical sync
			if(bus_state_.vsync) {
				vsync_counter_ = (vsync_counter_ + 1) & 15;
				if(vsync_counter_ == (registers_[3] >> 4)) {
					bus_state_.vsync = false;
				}
			}

			if(is_in_adjustment_period_) {
				line_counter_++;
				if(line_counter_ == registers_[5]) {
					is_in_adjustment_period_ = false;
					do_end_of_frame();
				}
			} else {
				// advance vertical counter
				if(bus_state_.row_address == registers_[9]) {
					bus_state_.row_address = 0;
					line_address_ = end_of_line_address_;

					// check for entry into the overflow area
					if(line_counter_ == registers_[4]) {
						if(registers_[5]) {
							line_counter_ = 0;
							is_in_adjustment_period_ = true;
						} else {
							do_end_of_frame();
						}
					} else {
						line_counter_ = (line_counter_ + 1) & 0x7f;

						// check for start of vertical sync
						if(line_counter_ == registers_[7]) {
							bus_state_.vsync = true;
							vsync_counter_ = 0;
						}

						// check for end of visible lines
						if(line_counter_ == registers_[6]) {
							line_is_visible_ = false;
						}
					}
				} else {
					bus_state_.row_address = (bus_state_.row_address + 1) & 0x1f;
				}
			}

			bus_state_.refresh_address = line_address_;
			character_counter_ = 0;
			character_is_visible_ = (registers_[1] != 0);
		}

		inline void do_end_of_frame() {
			line_counter_ = 0;
			line_is_visible_ = true;
			line_address_ = (uint16_t)((registers_[12] << 8) | registers_[13]);
			bus_state_.refresh_address = line_address_;
		}

		Personality personality_;
		T &bus_handler_;
		BusState bus_state_;

		uint8_t registers_[18];
		int selected_register_;

		uint8_t character_counter_;
		uint8_t line_counter_;

		bool character_is_visible_, line_is_visible_;

		int hsync_counter_;
		int vsync_counter_;
		bool is_in_adjustment_period_;

		uint16_t line_address_;
		uint16_t end_of_line_address_;
};

}
}

#endif /* CRTC6845_hpp */
<commit_msg>Eliminates repetition of the unpacking of register 3 into a horizontal sync count.<commit_after>//
//  CRTC6845.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/07/2017.
//  Copyright © 2017 Thomas Harte. All rights reserved.
//

#ifndef CRTC6845_hpp
#define CRTC6845_hpp

#include "../../ClockReceiver/ClockReceiver.hpp"

#include <cstdint>
#include <cstdio>

namespace Motorola {
namespace CRTC {

struct BusState {
	bool display_enable;
	bool hsync;
	bool vsync;
	bool cursor;
	uint16_t refresh_address;
	uint16_t row_address;
};

class BusHandler {
	public:
		/*!
			Performs the first phase of a 6845 bus cycle; this is the phase in which it is intended that
			systems using the 6845 respect the bus state and produce pixels, sync or whatever they require.
		*/
		void perform_bus_cycle_phase1(const BusState &) {}

		/*!
			Performs the second phase of a 6845 bus cycle. Some bus state — including sync — is updated
			directly after phase 1 and hence is visible to an observer during phase 2. Handlers may therefore
			implement @c perform_bus_cycle_phase2 to be notified of the availability of that state without
			having to wait until the next cycle has begun.
		*/
		void perform_bus_cycle_phase2(const BusState &) {}
};

enum Personality {
	HD6845S,	//
	UM6845R,	//
	MC6845,		//
	AMS40226	//
};

template <class T> class CRTC6845 {
	public:

		CRTC6845(Personality p, T &bus_handler) noexcept :
			personality_(p), bus_handler_(bus_handler) {}

		void select_register(uint8_t r) {
			selected_register_ = r;
		}

		uint8_t get_status() const {
			return 0xff;
		}

		uint8_t get_register() const {
			if(selected_register_ < 12 || selected_register_ > 17) return 0xff;
			return registers_[selected_register_];
		}

		void set_register(uint8_t value) {
			static uint8_t masks[] = {
				0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f,
				0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff
			};

			if(selected_register_ < 16)
				registers_[selected_register_] = value & masks[selected_register_];
		}

		void trigger_light_pen() {
			registers_[17] = bus_state_.refresh_address & 0xff;
			registers_[16] = bus_state_.refresh_address >> 8;
		}

		void run_for(Cycles cycles) {
			int cyles_remaining = cycles.as_int();
			while(cyles_remaining--) {
				// check for start of horizontal sync
				if(character_counter_ == registers_[2]) {
					hsync_counter_ = 0;
					bus_state_.hsync = true;
				}

				// check for end of horizontal sync; note that a sync time of zero will result in an immediate
				// cancellation of the plan to perform sync
				if(bus_state_.hsync) {
					bus_state_.hsync = hsync_counter_ != (registers_[3] & 15);
					hsync_counter_ = (hsync_counter_ + 1) & 15;
				}

				// check for end of visible characters
				if(character_counter_ == registers_[1]) {
					// TODO: consider skew in character_is_visible_. Or maybe defer until perform_bus_cycle?
					character_is_visible_ = false;
					end_of_line_address_ = bus_state_.refresh_address;
				}

				perform_bus_cycle_phase1();
				bus_state_.refresh_address = (bus_state_.refresh_address + 1) & 0x3fff;

				// check for end-of-line
				if(character_counter_ == registers_[0]) {
					character_counter_ = 0;
					do_end_of_line();
					character_is_visible_ = true;
				} else {
					// increment counter
					character_counter_++;
				}

				perform_bus_cycle_phase2();
			}
		}

		const BusState &get_bus_state() const {
			return bus_state_;
		}

	private:
		inline void perform_bus_cycle_phase1() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase1(bus_state_);
		}

		inline void perform_bus_cycle_phase2() {
			bus_state_.display_enable = character_is_visible_ && line_is_visible_;
			bus_handler_.perform_bus_cycle_phase2(bus_state_);
		}

		inline void do_end_of_line() {
			// check for end of vertical sync
			if(bus_state_.vsync) {
				vsync_counter_ = (vsync_counter_ + 1) & 15;
				if(vsync_counter_ == (registers_[3] >> 4)) {
					bus_state_.vsync = false;
				}
			}

			if(is_in_adjustment_period_) {
				line_counter_++;
				if(line_counter_ == registers_[5]) {
					is_in_adjustment_period_ = false;
					do_end_of_frame();
				}
			} else {
				// advance vertical counter
				if(bus_state_.row_address == registers_[9]) {
					bus_state_.row_address = 0;
					line_address_ = end_of_line_address_;

					// check for entry into the overflow area
					if(line_counter_ == registers_[4]) {
						if(registers_[5]) {
							line_counter_ = 0;
							is_in_adjustment_period_ = true;
						} else {
							do_end_of_frame();
						}
					} else {
						line_counter_ = (line_counter_ + 1) & 0x7f;

						// check for start of vertical sync
						if(line_counter_ == registers_[7]) {
							bus_state_.vsync = true;
							vsync_counter_ = 0;
						}

						// check for end of visible lines
						if(line_counter_ == registers_[6]) {
							line_is_visible_ = false;
						}
					}
				} else {
					bus_state_.row_address = (bus_state_.row_address + 1) & 0x1f;
				}
			}

			bus_state_.refresh_address = line_address_;
			character_counter_ = 0;
			character_is_visible_ = (registers_[1] != 0);
		}

		inline void do_end_of_frame() {
			line_counter_ = 0;
			line_is_visible_ = true;
			line_address_ = (uint16_t)((registers_[12] << 8) | registers_[13]);
			bus_state_.refresh_address = line_address_;
		}

		Personality personality_;
		T &bus_handler_;
		BusState bus_state_;

		uint8_t registers_[18];
		int selected_register_;

		uint8_t character_counter_;
		uint8_t line_counter_;

		bool character_is_visible_, line_is_visible_;

		int hsync_counter_;
		int vsync_counter_;
		bool is_in_adjustment_period_;

		uint16_t line_address_;
		uint16_t end_of_line_address_;
};

}
}

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


<commit_before>#ifndef __RIAK_RIAK_VALUE__
#define __RIAK_RIAK_VALUE__

#include "buffer_cache/blob.hpp"
#include "btree/node.hpp"

typedef uint32_t last_modified_time_t;

typedef uint32_t etag_t;

/* TODO there are a 3 ways that links could be put on disk
 *    Method                         Pros                Cons
 * 1: links just go in a blob        Space efficient     Queries take O(n)
 * 2: links go in a btree            Space inefficient   Queiries take Log(n) + m
 * 3: blob for few, btree for many   Best of both worlds We don't have it implemented
 *
 * The right way to do this is 3, for now we're doing 1. 2 will be easier to
 * write if the support operations throught riak like appending to values.
 * Riak's api does not support appending. */
#define MAX_LINK_SIZE 256
struct link_t {
    uint8_t bucket_len, key_len, tag_len;
    char contents[];

    const char *bucket() { return contents; }
    const char *key() { return contents + bucket_len; }
    const char *tag() { return contents + bucket_len + tag_len; }

    unsigned size() { return  bucket_len + key_len + tag_len; }
};

//notice this class does nothing to maintain its consistency
class riak_value_t {
public:
    last_modified_time_t mod_time;
    etag_t etag;
    uint16_t content_type_len;
    uint32_t value_len;
    uint16_t n_links;

    //contents
    char contents[];

    //contents is blob_t which has the follwing structure:
    // contents = content_type content (link)*

    void print(block_size_t block_size) {
        print_hd(this, 0, offsetof(riak_value_t, contents) + blob::ref_size(block_size, contents, blob::btree_maxreflen));
    }
};

#define MAX_RIAK_VALUE_SIZE (offsetof(riak_value_t, contents) + blob::btree_maxreflen)

template <>
class value_sizer_t<riak_value_t> : public value_sizer_t<void> {
public:
    value_sizer_t(block_size_t bs) : block_size_(bs) { }

    static const riak_value_t *as_riak(const void *v) {
        return reinterpret_cast<const riak_value_t *>(v);
    }

    // The number of bytes the value takes up.  Reference implementation:
    //
    // for (int i = 0; i < INT_MAX; ++i) {
    //    if (fits(value, i)) return i;
    // }
    int size(const void *value) const {
        return offsetof(riak_value_t, contents) + blob::ref_size(block_size_, as_riak(value)->contents, blob::btree_maxreflen);
    }

    // True if size(value) would return no more than length_available.
    // Does not read any bytes outside of [value, value +
    // length_available).
    bool fits(const void *value, int length_available) const {
        if (length_available < 0) { return false; }
        if ((unsigned) length_available < offsetof(riak_value_t, contents)) { return false; }
        else { return blob::ref_fits(block_size_, length_available - offsetof(riak_value_t, contents), as_riak(value)->contents, blob::btree_maxreflen); }
    }

    bool deep_fsck(UNUSED block_getter_t *getter, UNUSED const void *value,
                   UNUSED int length_available, UNUSED std::string *msg_out) const {
        // TODO LOOF: Add a real implementation here.
        return true;
    }

    int max_possible_size() const {
        return offsetof(riak_value_t, contents) + blob::btree_maxreflen;
    }

    static block_magic_t leaf_magic() {
        block_magic_t magic = { { 'r', 'i', 'a', 'k'} };
        return magic;
    }

    // The magic that should be used for btree leaf nodes (or general
    // nodes) with this kind of value.
    block_magic_t btree_leaf_magic() const {
        return leaf_magic();
    }

    block_size_t block_size() const { return block_size_; }

protected:
    // The block size.  It's convenient for leaf node code and for
    // some subclasses, too.
    block_size_t block_size_;
};

#endif
<commit_msg>Implemented deep_fsck for riak.<commit_after>#ifndef __RIAK_RIAK_VALUE__
#define __RIAK_RIAK_VALUE__

#include "buffer_cache/blob.hpp"
#include "btree/node.hpp"

typedef uint32_t last_modified_time_t;

typedef uint32_t etag_t;

/* TODO there are a 3 ways that links could be put on disk
 *    Method                         Pros                Cons
 * 1: links just go in a blob        Space efficient     Queries take O(n)
 * 2: links go in a btree            Space inefficient   Queiries take Log(n) + m
 * 3: blob for few, btree for many   Best of both worlds We don't have it implemented
 *
 * The right way to do this is 3, for now we're doing 1. 2 will be easier to
 * write if the support operations throught riak like appending to values.
 * Riak's api does not support appending. */
#define MAX_LINK_SIZE 256
struct link_t {
    uint8_t bucket_len, key_len, tag_len;
    char contents[];

    const char *bucket() { return contents; }
    const char *key() { return contents + bucket_len; }
    const char *tag() { return contents + bucket_len + tag_len; }

    unsigned size() { return  bucket_len + key_len + tag_len; }
};

//notice this class does nothing to maintain its consistency
class riak_value_t {
public:
    last_modified_time_t mod_time;
    etag_t etag;
    uint16_t content_type_len;
    uint32_t value_len;
    uint16_t n_links;

    //contents
    char contents[];

    //contents is blob_t which has the follwing structure:
    // contents = content_type content (link)*

    void print(block_size_t block_size) {
        print_hd(this, 0, offsetof(riak_value_t, contents) + blob::ref_size(block_size, contents, blob::btree_maxreflen));
    }
};

#define MAX_RIAK_VALUE_SIZE (offsetof(riak_value_t, contents) + blob::btree_maxreflen)

template <>
class value_sizer_t<riak_value_t> : public value_sizer_t<void> {
public:
    value_sizer_t(block_size_t bs) : block_size_(bs) { }

    static const riak_value_t *as_riak(const void *v) {
        return reinterpret_cast<const riak_value_t *>(v);
    }

    // The number of bytes the value takes up.  Reference implementation:
    //
    // for (int i = 0; i < INT_MAX; ++i) {
    //    if (fits(value, i)) return i;
    // }
    int size(const void *value) const {
        return offsetof(riak_value_t, contents) + blob::ref_size(block_size_, as_riak(value)->contents, blob::btree_maxreflen);
    }

    // True if size(value) would return no more than length_available.
    // Does not read any bytes outside of [value, value +
    // length_available).
    bool fits(const void *value, int length_available) const {
        if (length_available < 0) { return false; }
        if ((unsigned) length_available < offsetof(riak_value_t, contents)) { return false; }
        else { return blob::ref_fits(block_size_, length_available - offsetof(riak_value_t, contents), as_riak(value)->contents, blob::btree_maxreflen); }
    }

    bool deep_fsck(block_getter_t *getter, const void *value,
                   int length_available, std::string *msg_out) const {
        if (!fits(value, length_available)) {
            *msg_out = "value does not fit in length_available";
            return false;
        }

        return blob::deep_fsck(getter, block_size_, as_riak(value)->contents, blob::btree_maxreflen, msg_out);
    }

    int max_possible_size() const {
        return offsetof(riak_value_t, contents) + blob::btree_maxreflen;
    }

    static block_magic_t leaf_magic() {
        block_magic_t magic = { { 'r', 'i', 'a', 'k'} };
        return magic;
    }

    // The magic that should be used for btree leaf nodes (or general
    // nodes) with this kind of value.
    block_magic_t btree_leaf_magic() const {
        return leaf_magic();
    }

    block_size_t block_size() const { return block_size_; }

protected:
    // The block size.  It's convenient for leaf node code and for
    // some subclasses, too.
    block_size_t block_size_;
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

/*
 * Session management.
 */

#pragma once

#include "Id.hxx"

struct Session;
struct RealmSession;

/**
 * Finds the session with the specified id.  The returned object is
 * locked, and must be unlocked with session_put().
 */
Session *
session_get(SessionId id) noexcept;

/**
 * Unlocks the specified session.
 */
void
session_put(Session *session) noexcept;

void
session_put(RealmSession &session) noexcept;

class SessionLease {
	friend class RealmSessionLease;

	Session *session;

public:
	SessionLease() noexcept:session(nullptr) {}
	SessionLease(std::nullptr_t) noexcept:session(nullptr) {}

	explicit SessionLease(SessionId id) noexcept
		:session(session_get(id)) {}

	explicit SessionLease(Session *_session) noexcept
		:session(_session) {}

	SessionLease(SessionLease &&src) noexcept
		:session(src.session) {
		src.session = nullptr;
	}

	~SessionLease() noexcept {
		if (session != nullptr)
			session_put(session);
	}

	SessionLease &operator=(SessionLease &&src) noexcept {
		std::swap(session, src.session);
		return *this;
	}

	operator bool() const noexcept {
		return session != nullptr;
	}

	Session &operator *() const noexcept {
		return *session;
	}

	Session *operator->() const noexcept {
		return session;
	}

	Session *get() const noexcept {
		return session;
	}
};

class RealmSessionLease {
	RealmSession *session;

public:
	RealmSessionLease() noexcept:session(nullptr) {}
	RealmSessionLease(std::nullptr_t) noexcept:session(nullptr) {}

	RealmSessionLease(SessionLease &&src, const char *realm) noexcept;

	RealmSessionLease(SessionId id, const char *realm) noexcept;

	explicit RealmSessionLease(RealmSession *_session) noexcept
		:session(_session) {}

	RealmSessionLease(RealmSessionLease &&src) noexcept
		:session(src.session) {
		src.session = nullptr;
	}

	~RealmSessionLease() noexcept {
		if (session != nullptr)
			session_put(*session);
	}

	RealmSessionLease &operator=(RealmSessionLease &&src) noexcept {
		std::swap(session, src.session);
		return *this;
	}

	operator bool() const noexcept {
		return session != nullptr;
	}

	RealmSession &operator *() const noexcept {
		return *session;
	}

	RealmSession *operator->() const noexcept {
		return session;
	}

	RealmSession *get() const noexcept {
		return session;
	}
};
<commit_msg>bp/session/Lease: simplify initializers<commit_after>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

/*
 * Session management.
 */

#pragma once

#include "Id.hxx"

struct Session;
struct RealmSession;

/**
 * Finds the session with the specified id.  The returned object is
 * locked, and must be unlocked with session_put().
 */
Session *
session_get(SessionId id) noexcept;

/**
 * Unlocks the specified session.
 */
void
session_put(Session *session) noexcept;

void
session_put(RealmSession &session) noexcept;

class SessionLease {
	friend class RealmSessionLease;

	Session *session = nullptr;

public:
	SessionLease() noexcept = default;
	SessionLease(std::nullptr_t) noexcept {}

	explicit SessionLease(SessionId id) noexcept
		:session(session_get(id)) {}

	explicit SessionLease(Session *_session) noexcept
		:session(_session) {}

	SessionLease(SessionLease &&src) noexcept
		:session(std::exchange(src.session, nullptr)) {}

	~SessionLease() noexcept {
		if (session != nullptr)
			session_put(session);
	}

	SessionLease &operator=(SessionLease &&src) noexcept {
		using std::swap;
		swap(session, src.session);
		return *this;
	}

	operator bool() const noexcept {
		return session != nullptr;
	}

	Session &operator *() const noexcept {
		return *session;
	}

	Session *operator->() const noexcept {
		return session;
	}

	Session *get() const noexcept {
		return session;
	}
};

class RealmSessionLease {
	RealmSession *session = nullptr;

public:
	RealmSessionLease() noexcept = default;
	RealmSessionLease(std::nullptr_t) noexcept {}

	RealmSessionLease(SessionLease &&src, const char *realm) noexcept;

	RealmSessionLease(SessionId id, const char *realm) noexcept;

	explicit RealmSessionLease(RealmSession *_session) noexcept
		:session(_session) {}

	RealmSessionLease(RealmSessionLease &&src) noexcept
		:session(std::exchange(src.session, nullptr)) {}

	~RealmSessionLease() noexcept {
		if (session != nullptr)
			session_put(*session);
	}

	RealmSessionLease &operator=(RealmSessionLease &&src) noexcept {
		using std::swap;
		swap(session, src.session);
		return *this;
	}

	operator bool() const noexcept {
		return session != nullptr;
	}

	RealmSession &operator *() const noexcept {
		return *session;
	}

	RealmSession *operator->() const noexcept {
		return session;
	}

	RealmSession *get() const noexcept {
		return session;
	}
};
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
		if (a.is_v6()) return a.to_v6().is_link_local();
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000
			|| (ip & 0xfff00000) == 0xac100000
			|| (ip & 0xffff0000) == 0xc0a80000);
	}

	bool is_loopback(address const& addr)
	{
		if (addr.is_v4())
		  return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
	}

	bool is_multicast(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
	}

	bool is_any(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
		if (a1.is_v4() == a2.is_v4())
		{
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

		if (multicast_endpoint.address().is_v4())
			open_multicast_socket(ios, address_v4::any(), loopback);
		else
			open_multicast_socket(ios, address_v6::any(), loopback);

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only broadcast to IPv4 addresses that are not local
			if (is_local(i->interface_address)) continue;
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		if (addr.is_v4())
			s->open(udp::v4(), ec);
		else
			s->open(udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		if (addr.is_v4())
			s->set_option(outbound_interface(addr.to_v4()), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<commit_msg>fixed bug where broadcast socket would not send messages on interfaces with addresses in local network ranges<commit_after>/*

Copyright (c) 2007, 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 <boost/version.hpp>

#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif

#include <boost/bind.hpp>

#include "libtorrent/socket.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	bool is_local(address const& a)
	{
		if (a.is_v6()) return a.to_v6().is_link_local();
		address_v4 a4 = a.to_v4();
		unsigned long ip = a4.to_ulong();
		return ((ip & 0xff000000) == 0x0a000000
			|| (ip & 0xfff00000) == 0xac100000
			|| (ip & 0xffff0000) == 0xc0a80000);
	}

	bool is_loopback(address const& addr)
	{
		if (addr.is_v4())
		  return addr.to_v4() == address_v4::loopback();
		else
			return addr.to_v6() == address_v6::loopback();
	}

	bool is_multicast(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4().is_multicast();
		else
			return addr.to_v6().is_multicast();
	}

	bool is_any(address const& addr)
	{
		if (addr.is_v4())
			return addr.to_v4() == address_v4::any();
		else if (addr.to_v6().is_v4_mapped())
			return (addr.to_v6().to_v4() == address_v4::any());
		else
			return addr.to_v6() == address_v6::any();
	}

	address guess_local_address(io_service& ios)
	{
		// make a best guess of the interface we're using and its IP
		error_code ec;
		std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
		address ret = address_v4::any();
		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			address const& a = i->interface_address;
			if (is_loopback(a)
				|| is_multicast(a)
				|| is_any(a)) continue;

			// prefer a v4 address, but return a v6 if
			// there are no v4
			if (a.is_v4()) return a;

			if (ret != address_v4::any())
				ret = a;
		}
		return ret;
	}

	// count the length of the common bit prefix
	int common_bits(unsigned char const* b1
		, unsigned char const* b2, int n)
	{
		for (int i = 0; i < n; ++i, ++b1, ++b2)
		{
			unsigned char a = *b1 ^ *b2;
			if (a == 0) continue;
			int ret = i * 8 + 8;
			for (; a > 0; a >>= 1) --ret;
			return ret;
		}
		return n * 8;
	}

	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
		if (a1.is_v4() == a2.is_v4())
		{
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
		}

		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
	}

	broadcast_socket::broadcast_socket(io_service& ios
		, udp::endpoint const& multicast_endpoint
		, receive_handler_t const& handler
		, bool loopback)
		: m_multicast_endpoint(multicast_endpoint)
		, m_on_receive(handler)
	{
		TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));

		using namespace asio::ip::multicast;

		error_code ec;
		std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);

		if (multicast_endpoint.address().is_v4())
			open_multicast_socket(ios, address_v4::any(), loopback);
		else
			open_multicast_socket(ios, address_v6::any(), loopback);

		for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
			, end(interfaces.end()); i != end; ++i)
		{
			// only multicast on compatible networks
			if (i->interface_address.is_v4() != multicast_endpoint.address().is_v4()) continue;
			// ignore any loopback interface
			if (is_loopback(i->interface_address)) continue;

#ifndef NDEBUG
//			std::cerr << "broadcast socket [ if: " << i->interface_address.to_v4().to_string()
//				<< " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
			open_unicast_socket(ios, i->interface_address);
		}
	}

	void broadcast_socket::open_multicast_socket(io_service& ios
		, address const& addr, bool loopback)
	{
		using namespace asio::ip::multicast;

		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		if (addr.is_v4())
			s->open(udp::v4(), ec);
		else
			s->open(udp::v6(), ec);
		if (ec) return;
		s->set_option(datagram_socket::reuse_address(true), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
		if (ec) return;
		s->set_option(join_group(m_multicast_endpoint.address()), ec);
		if (ec) return;
		s->set_option(hops(255), ec);
		if (ec) return;
		s->set_option(enable_loopback(loopback), ec);
		if (ec) return;
		m_sockets.push_back(socket_entry(s));
		socket_entry& se = m_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		if (addr.is_v4())
			s->set_option(outbound_interface(addr.to_v4()), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}

	void broadcast_socket::send(char const* buffer, int size, error_code& ec)
	{
		for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
			, end(m_unicast_sockets.end()); i != end; ++i)
		{
			if (!i->socket) continue;
			error_code e;
			i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
//			std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl;
#endif
			if (e)
			{
				i->socket->close(e);
				i->socket.reset();
			}
		}
	}

	void broadcast_socket::on_receive(socket_entry* s, error_code const& ec
		, std::size_t bytes_transferred)
	{
		if (ec || bytes_transferred == 0 || !m_on_receive) return;
		m_on_receive(s->remote, s->buffer, bytes_transferred);
		if (!s->socket) return;
		s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
			, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
	}

	void broadcast_socket::close()
	{
		std::for_each(m_sockets.begin(), m_sockets.end(), bind(&socket_entry::close, _1));
		std::for_each(m_unicast_sockets.begin(), m_unicast_sockets.end(), bind(&socket_entry::close, _1));

		m_on_receive.clear();
	}
}

<|endoftext|>


<commit_before>#include <cmath>
#include <vector>
#include <algorithm>

#include "s-approximations.h"
#include "approximations-utils.h"

#define MAX_ITERATIONS = 1000

std::vector<double> _get_a(
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h
) {
    std::vector<double> a;

    for (int i = 1; i < x.size() - 1; i++) {
        a.push_back(
                (2 * _get_mid_val(D_s, i, false)) / (h[i - 1] * (x[i + 1] - x[i - 1]))
        );
    }

    return a;
}

std::vector<double> _get_b(
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h
) {
    std::vector<double> b;

    for (int i = 1; i < x.size() - 1; i++) {
        b.push_back(
                (2 * _get_mid_val(D_s, i, true)) / (h[i] * (x[i + 1] - x[i - 1]))
        );
    }

    return b;
}

std::vector<double> _get_c(
        double t_step,
        double C1,
        std::vector<double> a,
        std::vector<double> b
) {
    std::vector<double> c;

    for (int i = 1; i < a.size() - 1; i++) {
        c.push_back(
                a[i] + b[i] + (2 / t_step) + C1
        );
    }

    return c;
}

std::vector<double> _get_F(
        double t_step,
        double V_max,
        double K_m,
        std::vector<double> S_k,
        std::vector<double> y,
        std::vector<int> alpha,
        std::vector<double> f
) {
    std::vector<double> F;

    for (int i = 1; i < y.size() - 1; i++) {
        F.push_back(
                (2 * S_k[i] / t_step) - ( (alpha[i] * V_max * y[i]) / (K_m + y[i]) ) + _get_mid_val(f, i, true)
        );
    }

    return F;
}

double _get_new_y_0(
        std::vector<double> A,
        std::vector<double> B,
        std::vector<double> Y,
        double S_0,
        double q
) {
    double a = ((1 + q)^2) * (S_0 * B[1] + Y[1]) - (S_0 * B[2]) - Y[2];
    double b = ((1 + q)^2) * (1 - A[1]) + A[2] - 1;

    return a/b;
}

std::vector<double> _get_new_approximations(
        std::vector<double> S_k,
        std::vector<double> y_old,
        std::vector<double> A,
        std::vector<double> B,
        std::vector<double> Y,
        double t_step,
        double q,
        double delta
) {

    std::vector<double> y_new;
    int N = S_k.size();
    double S_0 = S_k[N-1];

    double y0 = _get_new_y_0(A, B, Y, S_0, q);

    y_new.push_back(yN);
    for (int i = 1; i < N - 1; i++) {
        y_new.push_back(
                y0 * A[i] + yN * B[i] + Y[i]
        );
    }
    y_new.push_back(S_0);

    return y_new;
}

void get_next_S(
        std::vector<double> S_k,
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h,
        std::vector<int> alpha,
        std::vector<double> f,
        double t_step,
        double V_max,
        double K_m,
        double C1,
        double q,
        double delta
) {

    std::vector<double> y_old = S_k;
    std::vector<double> y_new;
    double progress = 0;
    double residual = 0;
    double allowed_error = 0;
    int i = 0;

    do {
        if (i > MAX_ITERATIONS) {
            throw 100;
        }
        i++;

        std::vector<double> a = _get_a(D_s, x, h);
        std::vector<double> b = _get_b(D_s, x, h);
        std::vector<double> c = _get_c(t_step, C1, a, b);
        std::vector<double> F = _get_F(t_step, V_max, K_m, S_k, y_old, alpha, f);

        // ToDo calculate A,B,Y with lapac

        y_new = _get_new_approximations(S_k, y_old, A, B, Y, t_step, q, delta);

        std::vector<double> F_new = _get_F(t_step, V_max, K_m, S_k, y_old, alpha, f);

        progress = _get_progress(y_new, y_old);
        residual = _get_residual(y_new, a, b, c, F_new);
        allowed_error = _get_allowed_error(y_new, delta);

    } while (allowed_error > progress && allowed_error > residual);

    return y_new;
}

void approximate_s(
        std::vector<double> S_k,
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h,
        std::vector<double> t,
        std::vector<int> alpha,
        std::vector<double> f,
        double V_max,
        double K_m,
        double C1,
        double q,
        double delta
) {

    // ToDo for t get S_i
}
<commit_msg>Untested S approximation<commit_after>#include <cmath>
#include <vector>
#include <algorithm>

#include "s-approximations.h"
#include "approximations-utils.h"

#define MAX_ITERATIONS = 1000

std::vector<double> _get_a(
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h
) {
    std::vector<double> a;

    for (int i = 1; i < x.size() - 1; i++) {
        a.push_back(
                (2 * _get_mid_val(D_s, i, false)) / (h[i - 1] * (x[i + 1] - x[i - 1]))
        );
    }

    return a;
}

std::vector<double> _get_b(
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h
) {
    std::vector<double> b;

    for (int i = 1; i < x.size() - 1; i++) {
        b.push_back(
                (2 * _get_mid_val(D_s, i, true)) / (h[i] * (x[i + 1] - x[i - 1]))
        );
    }

    return b;
}

std::vector<double> _get_c(
        double t_step,
        double C1,
        std::vector<double> a,
        std::vector<double> b
) {
    std::vector<double> c;

    for (int i = 1; i < a.size() - 1; i++) {
        c.push_back(
                a[i] + b[i] + (2 / t_step) + C1
        );
    }

    return c;
}

std::vector<double> _get_F(
        double t_step,
        double V_max,
        double K_m,
        std::vector<double> S_k,
        std::vector<double> y,
        std::vector<int> alpha,
        std::vector<double> f
) {
    std::vector<double> F;

    for (int i = 1; i < y.size() - 1; i++) {
        F.push_back(
                (2 * S_k[i] / t_step) - ( (alpha[i] * V_max * y[i]) / (K_m + y[i]) ) + _get_mid_val(f, i, true)
        );
    }

    return F;
}

double _get_new_y_0(
        std::vector<double> A,
        std::vector<double> B,
        std::vector<double> Y,
        double S_0,
        double q
) {
    double a = ((1 + q)^2) * (S_0 * B[1] + Y[1]) - (S_0 * B[2]) - Y[2];
    double b = ((1 + q)^2) * (1 - A[1]) + A[2] - 1;

    return a/b;
}

std::vector<double> _get_new_approximations(
        std::vector<double> S_k,
        std::vector<double> y_old,
        std::vector<double> A,
        std::vector<double> B,
        std::vector<double> Y,
        double t_step,
        double q,
        double delta
) {

    std::vector<double> y_new;
    int N = S_k.size()-1;
    double S_0 = S_k[N];

    double y0 = _get_new_y_0(A, B, Y, S_0, q);

    y_new.push_back(yN);
    for (int i = 1; i < N-1; i++) {
        y_new.push_back(
                y0 * A[i] + yN * B[i] + Y[i]
        );
    }
    y_new.push_back(S_0);

    return y_new;
}

std::vector<double> get_zero_vector(int n) {
    std::vector<double> d(n);

    for(int i=0; i < n; i++) {
        d[i] = 0.0;
    }

    return d;
}

std::vector<double> slice(int from, int to, std::vector<double> vec) {
    std::vector<double> v(n);

    int j = 0;
    for(int i=start; i < to; i++) {
        v[j] = vec[i];
        j++;
    }
    return v;
}

std::vector<double> _solve_tridiagonal_matrix(
        std::vector<double> a,
        std::vector<double> b,
        std::vector<double> c,
        std::vector<double> d
) {
    int n = b.size();
    std::vector<double> a1 = slice(1, n, a);
    std::vector<double> c1 = slice(0, n, a);
    std::vector<double> b1 = slice(0, n-1, a);

    int info;
    int one = 1;
    std::vector<double> x(d);

    dgtsv_(&n, &one, &*a1.begin(), &*c1.begin(), &*b1.begin(), &*x.begin(), &n, &info);

    if (info != 0) {
        throw 200;
    }

    return x;
}

std::vector<double> _get_A(
        std::vector<double> a,
        std::vector<double> b,
        std::vector<double> c
) {
    std::vector<double> A;
    A.push_back(1);

    std::vector<double> tmp = _solve_tridiagonal_matrix(a, b, c, get_zero_vector(b.size());

    A.insert(A.back(), tmp);
    A.push_back(0);
    return A;
}

std::vector<double> _get_B(
        std::vector<double> a,
        std::vector<double> b,
        std::vector<double> c
) {
    std::vector<double> A;
    A.push_back(1);

    std::vector<double> tmp = _solve_tridiagonal_matrix(a, b, c, get_zero_vector(b.size());

    A.insert(A.back(), tmp);
    A.push_back(0);
    return A;
}

std::vector<double> _get_new_y(
        std::vector<double> S_k,
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h,
        std::vector<int> alpha,
        std::vector<double> f,
        double t_step,
        double V_max,
        double K_m,
        double C1,
        double q,
        double delta
) {
    std::vector<double> a = _get_a(D_s, x, h);
    std::vector<double> b = _get_b(D_s, x, h);
    std::vector<double> c = _get_c(t_step, C1, a, b);
    std::vector<double> F = _get_F(t_step, V_max, K_m, S_k, y_old, alpha, f);

    std::vector<double> A;
    std::vector<double> B;
    std::vector<double> Y;
    A.push_back(1);
    B.push_back(0);
    Y.push_back(0);

    std::vector<double> tmp_AB = _solve_tridiagonal_matrix(a, b, c, get_zero_vector(b.size());
    std::vector<double> tmp_Y = _solve_tridiagonal_matrix(a, b, c, F);

    A.insert(A.back(), tmp_AB);
    A.insert(B.back(), tmp_AB);
    Y.insert(Y.back(), tmp_Y);
    A.push_back(0);
    B.push_back(1);
    Y.push_back(0);

    return _get_new_approximations(S_k, y_old, A, B, Y, t_step, q, delta);
}

void _get_S_k_from_half_values(
        std::vector<double> S_k,
        std::vector<double> y
) {

    std::vector<double> S_k_next;

    for(int i = 0; i < S_k.size(); i++) {
        S_k_next.push_back(
                2*y[i] - S_k[i]
        );
    }

    return S_k_next;
}

std::vector<double> _get_next_S_k(
        std::vector<double> S_k,
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h,
        std::vector<int> alpha,
        std::vector<double> f,
        double t_step,
        double V_max,
        double K_m,
        double C1,
        double q,
        double delta
) {

    std::vector<double> y_old(S_k);
    std::vector<double> y_new;
    double progress = 0;
    double residual = 0;
    double allowed_error = 0;
    int i = 0;

    do {
        if (i > MAX_ITERATIONS) {
            throw 100;
        }
        i++;

        y_new = _get_new_y(S_k, D_s, x, h, alpha, f, t_step, V_max, K_m, C1, q, delta);
        std::vector<double> F_new = _get_F(t_step, V_max, K_m, S_k, y_old, alpha, f);

        progress = _get_progress(y_new, y_old);
        residual = _get_residual(y_new, a, b, c, F_new);
        allowed_error = _get_allowed_error(y_new, delta);

    } while (allowed_error > progress && allowed_error > residual);

    return _get_S_k_from_half_values(S_k, y_new);
}

std::vector<std::vector<double>> approximate_S(
        std::vector<double> D_s,
        std::vector<double> x,
        std::vector<double> h,
        std::vector<double> t,
        std::vector<int> alpha,
        std::vector<double> f,
        double S_0,
        double V_max,
        double K_m,
        double C1,
        double q,
        double delta
) {

    std::vector<std::vector<double>> S;
    std::vector<double> S_k = get_zero_vector(x.size()-1);
    S_k.push_back(S_0);

    for (int i = 1; i < t.size(); i++) {
        std::vector<double> S_i = _get_next_S_k(S_k, D_s, x, h, alpha, f, t_step, V_max, K_m, C1, q, delta);
        S.push_back(S_i);
        S_k(S_i);
    }

    return S;
}
<|endoftext|>