<commit_before>// Copyright (C) 2015 The Regents of the University of California (Regents).
// 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 Regents or University of California 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 HOLDERS 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.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/extract_maximally_parallel_rigid_subgraph.h"

#include <ceres/rotation.h>
#include <Eigen/Core>
#include <Eigen/LU>

#include <algorithm>
#include <unordered_map>
#include <vector>

#include "theia/sfm/pose/util.h"
#include "theia/sfm/types.h"
#include "theia/sfm/view_graph/view_graph.h"
#include "theia/util/map_util.h"

namespace theia {
namespace {

void FormAngleMeasurementMatrix(
    const std::unordered_map<ViewId, Eigen::Vector3d>& orientations,
    const ViewGraph& view_graph,
    const std::unordered_map<ViewId, int>& view_ids_to_index,
    Eigen::MatrixXd* angle_measurements) {
  const auto& view_pairs = view_graph.GetAllEdges();
  angle_measurements->setZero();

  // Set up the matrix such that t_{i,j} x (c_j - c_i) = 0.
  int i = 0;
  for (const auto& view_pair : view_pairs) {
    // Get t_{i,j} and rotate it such that it is oriented in the global
    // reference frame.
    Eigen::Matrix3d world_to_view1_rotation;
    ceres::AngleAxisToRotationMatrix(
        FindOrDie(orientations, view_pair.first.first).data(),
        ceres::ColumnMajorAdapter3x3(world_to_view1_rotation.data()));
    const Eigen::Vector3d rotated_translation =
        world_to_view1_rotation.transpose() * view_pair.second.position_2;
    const Eigen::Matrix3d cross_product_mat =
        CrossProductMatrix(rotated_translation);

    // Find the column locations of the two views.
    const int view1_col =
        3 * FindOrDie(view_ids_to_index, view_pair.first.first);
    const int view2_col =
        3 * FindOrDie(view_ids_to_index, view_pair.first.second);

    angle_measurements->block<3, 3>(3 * i, view1_col) = -cross_product_mat;
    angle_measurements->block<3, 3>(3 * i, view2_col) = cross_product_mat;
    ++i;
  }
}

// Computes the cosine distance in each dimension x, y, and z and returns the
// maximum cosine distance.
//
// cos distance = 1.0 - a.dot(b) / (norm(a) * norm(b))
double ComputeCosineDistance(const Eigen::MatrixXd& mat1,
                             const Eigen::MatrixXd& mat2) {
  Eigen::Vector3d cos_distance;
  for (int i =0; i < 3; i++) {
    cos_distance(i) = 1.0 - std::abs(mat1.row(0).dot(mat2.row(0)));
  }
  return cos_distance.maxCoeff();
}

// Find the maximal rigid component containing fixed_node. This is done by
// examining which nodes are parallel when removing node fixed_node from the
// null space. The nodes are only parallel if they are part of the maximal rigid
// component with fixed_node.
void FindMaximalParallelRigidComponent(const Eigen::MatrixXd& null_space,
                                       const int fixed_node,
                                       std::unordered_set<int>* largest_cc) {
  static const double kMaxCosDistance = 1e-5;
  static const double kMaxNorm = 1e-10;

  const int num_nodes = null_space.rows() / 3;

  largest_cc->insert(fixed_node);

  const Eigen::MatrixXd fixed_null_space_component =
    null_space.block(3 * fixed_node, 0, 3, null_space.cols());

  // Remove the fixed node from the rest of the null space.
  Eigen::MatrixXd modified_null_space =
      null_space - fixed_null_space_component.replicate(num_nodes, 1);

  // Normalize all rows to be unit-norm. If the rows have a very small norm then
  // they are parallel to the fixed_node. and should be set to zero.
  const Eigen::VectorXd norms = modified_null_space.rowwise().norm();

  modified_null_space.rowwise().normalize();

  // Find the pairs to match. Add all indices that are close to 0-vectors, as
  // they are clearly part of the rigid component.
  std::vector<int> indices_to_match;
  for (int i = 0; i < num_nodes; i++) {
    // Skip this index if it is fixed.
    if (i == fixed_node) {
      continue;
    }

    // Skip this index if it is nearly a 0-vector because this means it is
    // clearly part of the rigid component.
    if (norms(3 * i) < kMaxNorm &&
        norms(3 * i + 1) < kMaxNorm &&
        norms(3 * i + 2) < kMaxNorm) {
      largest_cc->insert(i);
      continue;
    }

    indices_to_match.emplace_back(i);
  }

  // Each node has three dimensions (x, y, z). We only compare parallel-ness
  // between similar dimensions. If all x, y, z dimensions are parallel then
  // the two nodes will be parallel.
  for (int i = 0; i < indices_to_match.size(); i++) {
    // Test all other nodes (that have not been tested) to determine if they are
    // parallel to this node.
    const Eigen::MatrixXd& block1 = modified_null_space.block(
        3 * indices_to_match[i], 0, 3, null_space.cols());

    for (int j = i + 1; j < indices_to_match.size(); j++) {
      const Eigen::MatrixXd& block2 = modified_null_space.block(
          3 * indices_to_match[j], 0, 3, null_space.cols());

      const double cos_distance = ComputeCosineDistance(block1, block2);
      if (cos_distance < kMaxCosDistance) {
        largest_cc->insert(indices_to_match[i]);
        largest_cc->insert(indices_to_match[j]);
      }
    }
  }
}

}  // namespace

void ExtractMaximallyParallelRigidSubgraph(
    const std::unordered_map<ViewId, Eigen::Vector3d>& orientations,
    ViewGraph* view_graph) {
  // Create a mapping of indexes to ViewIds for our linear system.
  std::unordered_map<ViewId, int> view_ids_to_index;
  view_ids_to_index.reserve(orientations.size());
  for (const auto& orientation : orientations) {
    const int current_index = view_ids_to_index.size();
    InsertIfNotPresent(&view_ids_to_index, orientation.first, current_index);
  }

  // Form the global angle measurements matrix from:
  //    t_{i,j} x (c_j - c_i) = 0.
  Eigen::MatrixXd angle_measurements(3 * view_graph->NumEdges(),
                                     3 * orientations.size());
  FormAngleMeasurementMatrix(orientations,
                             *view_graph,
                             view_ids_to_index,
                             &angle_measurements);

  // Extract the null space of the angle measurements matrix.
  Eigen::FullPivLU<Eigen::MatrixXd> lu(angle_measurements.transpose() *
                                       angle_measurements);
  const Eigen::MatrixXd null_space = lu.kernel();

  // For each node in the graph (i.e. each camera), set the null space component
  // to be zero such that the camera position would be fixed at the origin. If
  // two nodes i and j are in the same rigid component, then their null spaces
  // will be parallel because the camera positions may only change by a
  // scale. We find all components that are parallel to find the rigid
  // components. The largest of such component is the maximally parallel rigid
  // component of the graph.
  std::unordered_set<int> maximal_rigid_component;
  for (int i = 0; i < orientations.size(); i++) {
    std::unordered_set<int> temp_cc;
    FindMaximalParallelRigidComponent(null_space, i, &temp_cc);
    if (temp_cc.size() > maximal_rigid_component.size()) {
      std::swap(temp_cc, maximal_rigid_component);
    }
  }

  // Only keep the nodes in the largest maximally parallel rigid component.
  for (const auto& orientation : orientations) {
    const int index = FindOrDie(view_ids_to_index, orientation.first);
    // If the view is not in the maximal rigid component then remove it from the
    // view graph.
    if (!ContainsKey(maximal_rigid_component, index)) {
      CHECK(view_graph->RemoveView(orientation.first))
          << "Could not remove view id " << orientation.first
          << " from the view graph because it does not exist.";
    }
  }
}

}  // namespace theia
<commit_msg>Bug fix in cos distance function. Thanks to inspirit for spotting it!<commit_after>// Copyright (C) 2015 The Regents of the University of California (Regents).
// 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 Regents or University of California 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 HOLDERS 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.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/extract_maximally_parallel_rigid_subgraph.h"

#include <ceres/rotation.h>
#include <Eigen/Core>
#include <Eigen/LU>

#include <algorithm>
#include <unordered_map>
#include <vector>

#include "theia/sfm/pose/util.h"
#include "theia/sfm/types.h"
#include "theia/sfm/view_graph/view_graph.h"
#include "theia/util/map_util.h"

namespace theia {
namespace {

void FormAngleMeasurementMatrix(
    const std::unordered_map<ViewId, Eigen::Vector3d>& orientations,
    const ViewGraph& view_graph,
    const std::unordered_map<ViewId, int>& view_ids_to_index,
    Eigen::MatrixXd* angle_measurements) {
  const auto& view_pairs = view_graph.GetAllEdges();
  angle_measurements->setZero();

  // Set up the matrix such that t_{i,j} x (c_j - c_i) = 0.
  int i = 0;
  for (const auto& view_pair : view_pairs) {
    // Get t_{i,j} and rotate it such that it is oriented in the global
    // reference frame.
    Eigen::Matrix3d world_to_view1_rotation;
    ceres::AngleAxisToRotationMatrix(
        FindOrDie(orientations, view_pair.first.first).data(),
        ceres::ColumnMajorAdapter3x3(world_to_view1_rotation.data()));
    const Eigen::Vector3d rotated_translation =
        world_to_view1_rotation.transpose() * view_pair.second.position_2;
    const Eigen::Matrix3d cross_product_mat =
        CrossProductMatrix(rotated_translation);

    // Find the column locations of the two views.
    const int view1_col =
        3 * FindOrDie(view_ids_to_index, view_pair.first.first);
    const int view2_col =
        3 * FindOrDie(view_ids_to_index, view_pair.first.second);

    angle_measurements->block<3, 3>(3 * i, view1_col) = -cross_product_mat;
    angle_measurements->block<3, 3>(3 * i, view2_col) = cross_product_mat;
    ++i;
  }
}

// Computes the cosine distance in each dimension x, y, and z and returns the
// maximum cosine distance.
//
// cos distance = 1.0 - a.dot(b) / (norm(a) * norm(b))
double ComputeCosineDistance(const Eigen::MatrixXd& mat1,
                             const Eigen::MatrixXd& mat2) {
  Eigen::Vector3d cos_distance;
  for (int i =0; i < 3; i++) {
    cos_distance(i) = 1.0 - std::abs(mat1.row(i).dot(mat2.row(i)));
  }
  return cos_distance.maxCoeff();
}

// Find the maximal rigid component containing fixed_node. This is done by
// examining which nodes are parallel when removing node fixed_node from the
// null space. The nodes are only parallel if they are part of the maximal rigid
// component with fixed_node.
void FindMaximalParallelRigidComponent(const Eigen::MatrixXd& null_space,
                                       const int fixed_node,
                                       std::unordered_set<int>* largest_cc) {
  static const double kMaxCosDistance = 1e-5;
  static const double kMaxNorm = 1e-10;

  const int num_nodes = null_space.rows() / 3;

  largest_cc->insert(fixed_node);

  const Eigen::MatrixXd fixed_null_space_component =
    null_space.block(3 * fixed_node, 0, 3, null_space.cols());

  // Remove the fixed node from the rest of the null space.
  Eigen::MatrixXd modified_null_space =
      null_space - fixed_null_space_component.replicate(num_nodes, 1);

  // Normalize all rows to be unit-norm. If the rows have a very small norm then
  // they are parallel to the fixed_node. and should be set to zero.
  const Eigen::VectorXd norms = modified_null_space.rowwise().norm();

  modified_null_space.rowwise().normalize();

  // Find the pairs to match. Add all indices that are close to 0-vectors, as
  // they are clearly part of the rigid component.
  std::vector<int> indices_to_match;
  for (int i = 0; i < num_nodes; i++) {
    // Skip this index if it is fixed.
    if (i == fixed_node) {
      continue;
    }

    // Skip this index if it is nearly a 0-vector because this means it is
    // clearly part of the rigid component.
    if (norms(3 * i) < kMaxNorm &&
        norms(3 * i + 1) < kMaxNorm &&
        norms(3 * i + 2) < kMaxNorm) {
      largest_cc->insert(i);
      continue;
    }

    indices_to_match.emplace_back(i);
  }

  // Each node has three dimensions (x, y, z). We only compare parallel-ness
  // between similar dimensions. If all x, y, z dimensions are parallel then
  // the two nodes will be parallel.
  for (int i = 0; i < indices_to_match.size(); i++) {
    // Test all other nodes (that have not been tested) to determine if they are
    // parallel to this node.
    const Eigen::MatrixXd& block1 = modified_null_space.block(
        3 * indices_to_match[i], 0, 3, null_space.cols());

    for (int j = i + 1; j < indices_to_match.size(); j++) {
      const Eigen::MatrixXd& block2 = modified_null_space.block(
          3 * indices_to_match[j], 0, 3, null_space.cols());

      const double cos_distance = ComputeCosineDistance(block1, block2);
      if (cos_distance < kMaxCosDistance) {
        largest_cc->insert(indices_to_match[i]);
        largest_cc->insert(indices_to_match[j]);
      }
    }
  }
}

}  // namespace

void ExtractMaximallyParallelRigidSubgraph(
    const std::unordered_map<ViewId, Eigen::Vector3d>& orientations,
    ViewGraph* view_graph) {
  // Create a mapping of indexes to ViewIds for our linear system.
  std::unordered_map<ViewId, int> view_ids_to_index;
  view_ids_to_index.reserve(orientations.size());
  for (const auto& orientation : orientations) {
    const int current_index = view_ids_to_index.size();
    InsertIfNotPresent(&view_ids_to_index, orientation.first, current_index);
  }

  // Form the global angle measurements matrix from:
  //    t_{i,j} x (c_j - c_i) = 0.
  Eigen::MatrixXd angle_measurements(3 * view_graph->NumEdges(),
                                     3 * orientations.size());
  FormAngleMeasurementMatrix(orientations,
                             *view_graph,
                             view_ids_to_index,
                             &angle_measurements);

  // Extract the null space of the angle measurements matrix.
  Eigen::FullPivLU<Eigen::MatrixXd> lu(angle_measurements.transpose() *
                                       angle_measurements);
  const Eigen::MatrixXd null_space = lu.kernel();

  // For each node in the graph (i.e. each camera), set the null space component
  // to be zero such that the camera position would be fixed at the origin. If
  // two nodes i and j are in the same rigid component, then their null spaces
  // will be parallel because the camera positions may only change by a
  // scale. We find all components that are parallel to find the rigid
  // components. The largest of such component is the maximally parallel rigid
  // component of the graph.
  std::unordered_set<int> maximal_rigid_component;
  for (int i = 0; i < orientations.size(); i++) {
    std::unordered_set<int> temp_cc;
    FindMaximalParallelRigidComponent(null_space, i, &temp_cc);
    if (temp_cc.size() > maximal_rigid_component.size()) {
      std::swap(temp_cc, maximal_rigid_component);
    }
  }

  // Only keep the nodes in the largest maximally parallel rigid component.
  for (const auto& orientation : orientations) {
    const int index = FindOrDie(view_ids_to_index, orientation.first);
    // If the view is not in the maximal rigid component then remove it from the
    // view graph.
    if (!ContainsKey(maximal_rigid_component, index)) {
      CHECK(view_graph->RemoveView(orientation.first))
          << "Could not remove view id " << orientation.first
          << " from the view graph because it does not exist.";
    }
  }
}

}  // namespace theia
<|endoftext|>


<commit_before>#ifndef ITER_ENUMERATE_H_
#define ITER_ENUMERATE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <functional>
#include <initializer_list>
#include <type_traits>

namespace iter {
  namespace impl {
    template <typename Container>
    class Enumerable;

    using EnumerateFn = IterToolFn<Enumerable>;
  }
  constexpr impl::EnumerateFn enumerate;
}

template <typename Container>
class iter::impl::Enumerable {
 private:
  Container container;
  const std::size_t start;

  friend EnumerateFn;

  // for IterYield
  using BasePair = std::pair<std::size_t, iterator_deref<Container>>;

  // Value constructor for use only in the enumerate function
  Enumerable(Container&& in_container, std::size_t in_start = 0)
      : container(std::forward<Container>(in_container)), start{in_start} {}

 public:
  Enumerable(Enumerable&&) = default;

  // "yielded" by the Enumerable::Iterator.  Has a .index, and a
  // .element referencing the value yielded by the subiterator
  class IterYield : public BasePair {
   public:
    using BasePair::BasePair;
    typename BasePair::first_type& index = BasePair::first;
    typename BasePair::second_type& element = BasePair::second;
  };

  //  Holds an iterator of the contained type and a size_t for the
  //  index.  Each call to ++ increments both of these data members.
  //  Each dereference returns an IterYield.
  class Iterator : public std::iterator<std::input_iterator_tag, IterYield> {
   private:
    iterator_type<Container> sub_iter;
    std::size_t index;

   public:
    Iterator(iterator_type<Container>&& si, std::size_t start)
        : sub_iter{std::move(si)}, index{start} {}

    IterYield operator*() {
      return {this->index, *this->sub_iter};
    }

    ArrowProxy<IterYield> operator->() {
      return {**this};
    }

    Iterator& operator++() {
      ++this->sub_iter;
      ++this->index;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), start};
  }

  Iterator end() {
    return {std::end(this->container), start};
  }
};

#endif
<commit_msg>explicit {} on enumerate init<commit_after>#ifndef ITER_ENUMERATE_H_
#define ITER_ENUMERATE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <functional>
#include <initializer_list>
#include <type_traits>

namespace iter {
  namespace impl {
    template <typename Container>
    class Enumerable;

    using EnumerateFn = IterToolFn<Enumerable>;
  }
  constexpr impl::EnumerateFn enumerate{};
}

template <typename Container>
class iter::impl::Enumerable {
 private:
  Container container;
  const std::size_t start;

  friend EnumerateFn;

  // for IterYield
  using BasePair = std::pair<std::size_t, iterator_deref<Container>>;

  // Value constructor for use only in the enumerate function
  Enumerable(Container&& in_container, std::size_t in_start = 0)
      : container(std::forward<Container>(in_container)), start{in_start} {}

 public:
  Enumerable(Enumerable&&) = default;

  // "yielded" by the Enumerable::Iterator.  Has a .index, and a
  // .element referencing the value yielded by the subiterator
  class IterYield : public BasePair {
   public:
    using BasePair::BasePair;
    typename BasePair::first_type& index = BasePair::first;
    typename BasePair::second_type& element = BasePair::second;
  };

  //  Holds an iterator of the contained type and a size_t for the
  //  index.  Each call to ++ increments both of these data members.
  //  Each dereference returns an IterYield.
  class Iterator : public std::iterator<std::input_iterator_tag, IterYield> {
   private:
    iterator_type<Container> sub_iter;
    std::size_t index;

   public:
    Iterator(iterator_type<Container>&& si, std::size_t start)
        : sub_iter{std::move(si)}, index{start} {}

    IterYield operator*() {
      return {this->index, *this->sub_iter};
    }

    ArrowProxy<IterYield> operator->() {
      return {**this};
    }

    Iterator& operator++() {
      ++this->sub_iter;
      ++this->index;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), start};
  }

  Iterator end() {
    return {std::end(this->container), start};
  }
};

#endif
<|endoftext|>


<commit_before>/*
 * File:  btree.cpp
 * Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "common/sedna.h"

#include "tr/idx/btree/btree.h"
#include "tr/idx/btree/btintern.h"
#include "tr/idx/btree/btpage.h"
#include "tr/idx/btree/btstruct.h"
#include "tr/vmm/vmm.h"

/* variables for debug */
//shft	BTREE_HEIGHT=1;

xptr bt_create(xmlscm_type t)
{
    xptr    root;
    char*   pg;

    vmm_alloc_data_block(&root);
    pg = (char*)XADDR(root);
    bt_page_markup(pg, t);
    return root;
}

void bt_drop(const xptr &root)
{
    char*   cur_pg;
    xptr    cur_xpg = root;

    do {
        CHECKP(cur_xpg);
        cur_pg = (char*)XADDR(cur_xpg);
        xptr next_level_lmp = BT_LMP(cur_pg);
        if ((next_level_lmp == XNULL) && !BT_IS_LEAF(cur_pg))
            throw USER_EXCEPTION2(SE1008, "Encountered XNULL LMP field when trying to get left-most path in btree");

        /* walk through pages at current layer */
        do {
            xptr tmp = cur_xpg;
            CHECKP(cur_xpg);
            cur_xpg = BT_NEXT(cur_pg);
            cur_pg = (char*)XADDR(cur_xpg);
            vmm_delete_block(tmp);
        } while (cur_xpg != XNULL);

        cur_xpg = next_level_lmp;
    } while (cur_xpg != XNULL);
}

bt_cursor bt_find(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr res_blk = root;

    CHECKP(res_blk);
    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc) /* no matching key */
        return bt_cursor();
    else
        return bt_cursor((char*)XADDR(res_blk), key_idx);
}

/// !!! potential error here
bt_cursor bt_find_ge(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr next;
    xptr res_blk = root;

    CHECKP(res_blk);
    char* pg = (char*)XADDR(res_blk);

    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc && key_idx == BT_RIGHTMOST)
    {
#ifdef PERMIT_CLUSTERS
        if (BT_IS_CLUS(pg))
        {
            pg = bt_cluster_tail(pg);
            if (BT_KEY_NUM(pg) > 1) return bt_cursor(pg, 1);
        }
#endif
        next = BT_NEXT(pg);
        if (next != XNULL)
        {
            CHECKP(next);
            return bt_cursor((char*)XADDR(next), 0);
        }
        else return bt_cursor();
    }
    else return bt_cursor((char*)XADDR(res_blk), key_idx);
}

/// !!! potential error here
bt_cursor bt_find_gt(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr next;
    xptr res_blk = root;
	bt_key old_val=key;
    CHECKP(res_blk);
    char* pg = (char*)XADDR(res_blk);

    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc && key_idx == BT_RIGHTMOST)
    {
#ifdef PERMIT_CLUSTERS
        if (BT_IS_CLUS(pg))
        {
            pg = bt_cluster_tail(pg);
            if (BT_KEY_NUM(pg) > 1) return bt_cursor(pg, 1);
        }
#endif
        next = BT_NEXT(pg);
        if (next != XNULL)
        {
            CHECKP(next);
            return bt_cursor((char*)XADDR(next), 0);
		}
        else return bt_cursor();
    }
    else
    {
        bt_cursor c((char*)XADDR(res_blk), key_idx);
		if (!bt_cmp_key(c.get_key(),old_val))
		{
			c.bt_next_key();
			return c;
		}
		else
		{
			return c;
		}
    }
}

bt_cursor bt_lm(const xptr& root)
{
    CHECKP(root);
    char* pg = (char*)XADDR(root);

#ifdef PERMIT_CLUSTERS
    /// !!! FIX ME UP
#endif

    if (!BT_IS_LEAF(pg))
    {
        return bt_lm(BT_LMP(pg));
	}
    else
    {
        return bt_cursor(pg, 0);
    }
}

void bt_insert(xptr &root, const bt_key &key, const object &obj)
{
    bool  rc;
    shft  key_idx = 0;
    shft  obj_idx = 0;
    xptr  insert_xpg = root; /* xptr passed to search functions, that can change, pointing to insert new data */
    char* insert_pg;

    /* check key length doesn't exceed limit */
    if (key.get_size() >= BT_PAGE_PAYLOAD / 2)
        throw USER_EXCEPTION2(SE1008, "The size of the index key exceeds max key limit");

    rc = bt_find_key(insert_xpg, (bt_key*)&key, key_idx);
    /* page could change */
    insert_pg = (char*)XADDR(insert_xpg);

    if (rc)
    {
        rc = bt_leaf_find_obj(insert_xpg, obj, key_idx, obj_idx);

      /*  if (rc) throw USER_EXCEPTION2(SE1008, "The key/object pair already exists in btree");
        else
        {*/
            CHECKP(insert_xpg);
            insert_pg = (char*)XADDR(insert_xpg);

            if (obj_idx == BT_RIGHTMOST)
                obj_idx = *((shft*)BT_CHNK_TAB_AT(insert_pg, key_idx) + 1);

            bt_leaf_insert(root, insert_pg, key_idx, false, key, obj, obj_idx);
        /*}*/
    }
    else
    {
        CHECKP(insert_xpg);

        if (key_idx == BT_RIGHTMOST)
            key_idx = BT_KEY_NUM(insert_pg);
        bt_leaf_insert(root, insert_pg, key_idx, true, key, obj, obj_idx);
    }
}

void bt_modify(xptr &root, const bt_key &old_key, const bt_key &new_key, const object &obj)
{
    bt_delete(root, old_key, obj);
    bt_insert(root, new_key, obj);
}

/* light delete functions - delete only data from pages, not droping the pages, i.e no
   implementation of page merge/drop
 */
/* delete key/obj pair */
void bt_delete(xptr &root, const bt_key& key, const object &obj)
{
    bool    rc;
    shft    key_idx;
    shft    obj_idx;
    xptr    delete_xpg = root; /* xptr passed to search functions, that can change, pointing to page where data resides */
    char*   delete_pg = (char*)XADDR(delete_xpg);

    CHECKP(delete_xpg);

    rc = bt_find_key(delete_xpg, (bt_key*)&key, key_idx);
    if (rc)
    {
        rc = bt_leaf_find_obj(delete_xpg, obj, key_idx, obj_idx);
        /* page could change */
        CHECKP(delete_xpg);
        delete_pg = (char*)XADDR(delete_xpg);
        if (rc) bt_delete_obj(delete_pg, key_idx, obj_idx);
        else throw USER_EXCEPTION2(SE1008, "Cannot delete object which is not in the btree");
    }
    else throw USER_EXCEPTION2(SE1008, "Cannot delete object which is not in the btree");
}

/* delete key and all associated objects */
void bt_delete(xptr &root, const bt_key &key)
{
    bool    rc;
    shft    key_idx;
    xptr    delete_xpg = root; /* xptr passed to search functions, that can change, pointing to page where data resides */
    char*   delete_pg = (char*)XADDR(delete_xpg);

    CHECKP(delete_xpg);

    rc = bt_find_key(delete_xpg, (bt_key*)&key, key_idx);
    if (rc)
    { /* page could change */
        CHECKP(delete_xpg);
        delete_pg = (char*)XADDR(delete_xpg);
        bt_leaf_delete_key(delete_pg, key_idx);
    }
}
/* drop empty page*/
void           bt_drop_page(const btree_blk_hdr * pg)
{
	xptr page=ADDR2XPTR(pg);
	btree_blk_hdr * page_hdr= (btree_blk_hdr*)XADDR(page);
	xptr left=page_hdr->prev;
	xptr right=page_hdr->next;
	//1. fixing block chain
	if (left!=XNULL)
	{
		CHECKP(left);
		((btree_blk_hdr*)XADDR(left))->next=right;
		VMM_SIGNAL_MODIFICATION(left);

	}
	if (right!=XNULL)
	{
		CHECKP(right);
		((btree_blk_hdr*)XADDR(right))->prev=left;
		VMM_SIGNAL_MODIFICATION(right);

	}
	//remove key from upper layers
	xptr parent=page_hdr->parent;
	if (parent==XNULL)
		return;
	vmm_delete_block(page);
	CHECKP(parent);
	btree_blk_hdr * par_hdr= (btree_blk_hdr*)XADDR(parent);
	// fix lmp
	if (par_hdr->lmp==page)
		par_hdr->lmp=right;
	//find key by xptr
	int key_idx=-1;
	for (int i=0;i<BT_KEY_NUM(par_hdr);i++)
	{
		if (page==( *(xptr*)BT_BIGPTR_TAB_AT((char*)par_hdr, i)))
		{
			key_idx=i;
			break;
		}
	}
	if (key_idx<0)
		throw USER_EXCEPTION2(SE1008, "System error in indexes");

	bt_nleaf_delete_key((char*)par_hdr,key_idx);
	//VMM_SIGNAL_MODIFICATION(parent);
	//recursive walthrough
	if (!BT_KEY_NUM(par_hdr))  bt_drop_page(par_hdr);
}
<commit_msg>bug fix in btrees<commit_after>/*
 * File:  btree.cpp
 * Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "common/sedna.h"

#include "tr/idx/btree/btree.h"
#include "tr/idx/btree/btintern.h"
#include "tr/idx/btree/btpage.h"
#include "tr/idx/btree/btstruct.h"
#include "tr/idx/btree/buff.h"
#include "tr/vmm/vmm.h"

/* variables for debug */
//shft	BTREE_HEIGHT=1;

xptr bt_create(xmlscm_type t)
{
    xptr    root;
    char*   pg;

    vmm_alloc_data_block(&root);
    pg = (char*)XADDR(root);
    bt_page_markup(pg, t);
    return root;
}

void bt_drop(const xptr &root)
{
    char*   cur_pg;
    xptr    cur_xpg = root;

    do {
        CHECKP(cur_xpg);
        cur_pg = (char*)XADDR(cur_xpg);
        xptr next_level_lmp = BT_LMP(cur_pg);
        if ((next_level_lmp == XNULL) && !BT_IS_LEAF(cur_pg))
            throw USER_EXCEPTION2(SE1008, "Encountered XNULL LMP field when trying to get left-most path in btree");

        /* walk through pages at current layer */
        do {
            xptr tmp = cur_xpg;
            CHECKP(cur_xpg);
            cur_xpg = BT_NEXT(cur_pg);
            cur_pg = (char*)XADDR(cur_xpg);
            vmm_delete_block(tmp);
        } while (cur_xpg != XNULL);

        cur_xpg = next_level_lmp;
    } while (cur_xpg != XNULL);
}

bt_cursor bt_find(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr res_blk = root;

    CHECKP(res_blk);
    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc) /* no matching key */
        return bt_cursor();
    else
        return bt_cursor((char*)XADDR(res_blk), key_idx);
}

/// !!! potential error here
bt_cursor bt_find_ge(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr next;
    xptr res_blk = root;

    CHECKP(res_blk);
    char* pg = (char*)XADDR(res_blk);

    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc && key_idx == BT_RIGHTMOST)
    {
#ifdef PERMIT_CLUSTERS
        if (BT_IS_CLUS(pg))
        {
            pg = bt_cluster_tail(pg);
            if (BT_KEY_NUM(pg) > 1) return bt_cursor(pg, 1);
        }
#endif
        next = BT_NEXT(pg);
        if (next != XNULL)
        {
            CHECKP(next);
            return bt_cursor((char*)XADDR(next), 0);
        }
        else return bt_cursor();
    }
    else return bt_cursor((char*)XADDR(res_blk), key_idx);
}

/// !!! potential error here
bt_cursor bt_find_gt(const xptr &root, const bt_key &key)
{
    bool rc;
    shft key_idx;
    xptr next;
    xptr res_blk = root;
	bt_key old_val=key;
    CHECKP(res_blk);
    char* pg = (char*)XADDR(res_blk);

    rc = bt_find_key(res_blk, (bt_key*)&key, key_idx);
    if (!rc && key_idx == BT_RIGHTMOST)
    {
#ifdef PERMIT_CLUSTERS
        if (BT_IS_CLUS(pg))
        {
            pg = bt_cluster_tail(pg);
            if (BT_KEY_NUM(pg) > 1) return bt_cursor(pg, 1);
        }
#endif
        next = BT_NEXT(pg);
        if (next != XNULL)
        {
            CHECKP(next);
            return bt_cursor((char*)XADDR(next), 0);
		}
        else return bt_cursor();
    }
    else
    {
        bt_cursor c((char*)XADDR(res_blk), key_idx);
		if (!bt_cmp_key(c.get_key(),old_val))
		{
			c.bt_next_key();
			return c;
		}
		else
		{
			return c;
		}
    }
}

bt_cursor bt_lm(const xptr& root)
{
    CHECKP(root);
    char* pg = (char*)XADDR(root);

#ifdef PERMIT_CLUSTERS
    /// !!! FIX ME UP
#endif

    if (!BT_IS_LEAF(pg))
    {
        return bt_lm(BT_LMP(pg));
	}
    else
    {
        return bt_cursor(pg, 0);
    }
}

void bt_insert(xptr &root, const bt_key &key, const object &obj)
{
    bool  rc;
    shft  key_idx = 0;
    shft  obj_idx = 0;
    xptr  insert_xpg = root; /* xptr passed to search functions, that can change, pointing to insert new data */
    char* insert_pg;

    /* check key length doesn't exceed limit */
    if (key.get_size() >= BT_PAGE_PAYLOAD / 2)
        throw USER_EXCEPTION2(SE1008, "The size of the index key exceeds max key limit");

    rc = bt_find_key(insert_xpg, (bt_key*)&key, key_idx);
    /* page could change */
    insert_pg = (char*)XADDR(insert_xpg);

    if (rc)
    {
        rc = bt_leaf_find_obj(insert_xpg, obj, key_idx, obj_idx);

      /*  if (rc) throw USER_EXCEPTION2(SE1008, "The key/object pair already exists in btree");
        else
        {*/
            CHECKP(insert_xpg);
            insert_pg = (char*)XADDR(insert_xpg);

            if (obj_idx == BT_RIGHTMOST)
                obj_idx = *((shft*)BT_CHNK_TAB_AT(insert_pg, key_idx) + 1);

            bt_leaf_insert(root, insert_pg, key_idx, false, key, obj, obj_idx);
        /*}*/
    }
    else
    {
        CHECKP(insert_xpg);

        if (key_idx == BT_RIGHTMOST)
            key_idx = BT_KEY_NUM(insert_pg);
        bt_leaf_insert(root, insert_pg, key_idx, true, key, obj, obj_idx);
    }
}

void bt_modify(xptr &root, const bt_key &old_key, const bt_key &new_key, const object &obj)
{
    bt_delete(root, old_key, obj);
    bt_insert(root, new_key, obj);
}

/* light delete functions - delete only data from pages, not droping the pages, i.e no
   implementation of page merge/drop
 */
/* delete key/obj pair */
void bt_delete(xptr &root, const bt_key& key, const object &obj)
{
    bool    rc;
    shft    key_idx;
    shft    obj_idx;
    xptr    delete_xpg = root; /* xptr passed to search functions, that can change, pointing to page where data resides */
    char*   delete_pg = (char*)XADDR(delete_xpg);

    CHECKP(delete_xpg);

    rc = bt_find_key(delete_xpg, (bt_key*)&key, key_idx);
    if (rc)
    {
        rc = bt_leaf_find_obj(delete_xpg, obj, key_idx, obj_idx);
        /* page could change */
        CHECKP(delete_xpg);
        delete_pg = (char*)XADDR(delete_xpg);
        if (rc) bt_delete_obj(delete_pg, key_idx, obj_idx);
        else throw USER_EXCEPTION2(SE1008, "Cannot delete object which is not in the btree");
    }
    else throw USER_EXCEPTION2(SE1008, "Cannot delete object which is not in the btree");
}

/* delete key and all associated objects */
void bt_delete(xptr &root, const bt_key &key)
{
    bool    rc;
    shft    key_idx;
    xptr    delete_xpg = root; /* xptr passed to search functions, that can change, pointing to page where data resides */
    char*   delete_pg = (char*)XADDR(delete_xpg);

    CHECKP(delete_xpg);

    rc = bt_find_key(delete_xpg, (bt_key*)&key, key_idx);
    if (rc)
    { /* page could change */
        CHECKP(delete_xpg);
        delete_pg = (char*)XADDR(delete_xpg);
        bt_leaf_delete_key(delete_pg, key_idx);
    }
}
/* drop empty page*/
void           bt_drop_page(const btree_blk_hdr * pg)
{
	xptr page=ADDR2XPTR(pg);
	btree_blk_hdr * page_hdr= (btree_blk_hdr*)XADDR(page);
	xptr left=page_hdr->prev;
	xptr right=page_hdr->next;
	//1. fixing block chain
	if (left!=XNULL)
	{
		CHECKP(left);
		((btree_blk_hdr*)XADDR(left))->next=right;
		VMM_SIGNAL_MODIFICATION(left);

	}
	if (right!=XNULL)
	{
		CHECKP(right);
		((btree_blk_hdr*)XADDR(right))->prev=left;
		VMM_SIGNAL_MODIFICATION(right);

	}
	//remove key from upper layers
	xptr parent=page_hdr->parent;
	if (parent==XNULL)
		return;
	vmm_delete_block(page);
	CHECKP(parent);
	btree_blk_hdr * par_hdr= (btree_blk_hdr*)XADDR(parent);
	// fix lmp
	if (par_hdr->lmp==page)
		par_hdr->lmp=right;
	//find key by xptr
	int key_idx=-1;
	for (int i=0;i<BT_KEY_NUM(par_hdr);i++)
	{
		if (page==( *(xptr*)BT_BIGPTR_TAB_AT((char*)par_hdr, i)))
		{
			key_idx=i;
			break;
		}
	}
	if (key_idx<0)
		throw USER_EXCEPTION2(SE1008, "System error in indexes");

	bt_nleaf_delete_key((char*)par_hdr,key_idx);
	//VMM_SIGNAL_MODIFICATION(parent);
	//recursive walthrough
	if (!BT_KEY_NUM(par_hdr))
	{
		if (par_hdr->lmp!=XNULL)
		{
			//the case whe only one pointer left in non-leaf page
			xptr grandpa=par_hdr->parent;//save parent
			xptr left_unc=par_hdr->prev;//save left
			xptr right_unc=par_hdr->next;//save right
			xptr lmp=par_hdr->lmp;
			CHECKP(lmp);
			char*   dst = bt_tune_buffering(true, 4);
			memcpy(dst,(char*)XADDR(lmp)+sizeof(vmm_sm_blk_hdr),PAGE_SIZE-sizeof(vmm_sm_blk_hdr));
			CHECKP(parent);
			memcpy((char*)XADDR(parent)+sizeof(vmm_sm_blk_hdr),dst,PAGE_SIZE-sizeof(vmm_sm_blk_hdr));
			par_hdr->parent=grandpa;//restore
			par_hdr->prev=left_unc;
			par_hdr->next=right_unc;
			VMM_SIGNAL_MODIFICATION(parent);
			vmm_delete_block(lmp);

		}
		else
			bt_drop_page(par_hdr);
	}
}
<|endoftext|>


<commit_before>/*
 * File:  other_updates.cpp
 * Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "common/sedna.h"

#include "tr/updates/updates.h"
#include "tr/executor/base/xptr_sequence.h"
#include "tr/mo/mo.h"
#include "tr/auth/auc.h"
#include "tr/locks/locks.h"

#ifdef SE_ENABLE_TRIGGERS
#include "tr/triggers/triggers.h"
#endif

#include "tr/structures/nodeutils.h"
#include "tr/structures/textcptr.h"

void replace(PPOpIn arg)
{
    xptr node, parent, tmp_node, old_node, node_child, del_node, attr_node;
    schema_node_xptr scm_node;
    tuple t(arg.ts);

    xptr_sequence arg1seq;        // Indirection of nodes which are going to be replaced
    xptr_sequence arg1seq_tmp;    // Nodes which are going to be replaced
    xptr_sequence arg2seq;        // Nodes to replace with (both persistent and temp)

    /* Persistent nodes to replace with (+ theirs position in arg2seq) */
    descript_sequence arg3seq(2);

    upd_ns_map* ins_swiz = NULL;
    bool is_node_updated = true;

    /*
     * Fill up sequences with nodes to update and update with,
     * child (arg) returns the following sequence of items:
     * 1. node to be replaced (1)
     * 2. nodes to replace with (2)
     * 3. special tuple which contains separator value (3)
     */
    arg.op->next(t);

    while (!t.is_eos())
    {
        if (t.cells[0].is_node())
        {
            node=t.cells[0].get_node();
            CHECKP(node);
            /*
             * In (1) case node must be persistent (is_node_updated is true)
             * In (2) case it can be temporary
             * In both cases document nodes are not allowed
             */
            if ((!is_node_updated || is_node_persistent(node)) && !is_node_document(node))
            {
                xptr indir=nodeGetIndirection(node);

                if (is_node_updated)
                {
                    /* Case (1) - fill up sequence with nodes to be replaced */
                    is_node_updated=false;
                    /* Next nodes from arg are case (2) nodes, so we can use shared lock */
                    local_lock_mrg->lock(lm_s);
                    arg1seq.add(indir);
                    arg1seq_tmp.add(node);
                }
                else
                {
                    /* Case (2) - fill up sequence with nodes to replace with */
                    if (is_node_persistent(node))
                    {
                        tuple tup(2);
                        tup.copy(tuple_cell::node(node),tuple_cell((int64_t)(arg2seq.size())));
                        arg3seq.add(tup);
                    }
                    arg2seq.add(indir);
                }
            }
#ifndef IGNORE_UPDATE_ERRORS
            else
            {
                throw USER_EXCEPTION(SE2020);
            }
#endif
        }
        else
        {
            /* Must be separator in this case (3) */
            if (t.cells[0].get_atomic_type() == se_separator)
            {
                arg2seq.add(XNULL);
                is_node_updated=true;
                /* Next nodes from arg are case (1) node, so we can use shared lock */
                local_lock_mrg->lock(lm_x);
            }
#ifndef IGNORE_UPDATE_ERRORS
            else throw USER_EXCEPTION(SE2021);
#endif
        }

        arg.op->next(t);
    }

    /* Nothing to do in this case */
    if (arg1seq.size()<=0) return;

    /* Checking authorization */
    if (is_auth_check_needed(REPLACE_STATEMENT))
        auth_for_update(&arg1seq, REPLACE_STATEMENT, false);

    /* Find all common nodes in agr3seq (nodes to replace with) and
    * arg1seq_tmp (nodes to be replaced). Make a copy of all such nodes. */
    arg1seq_tmp.sort();
    arg3seq.sort();
    descript_sequence::iterator it3 = arg3seq.begin();
    xptr_sequence::iterator     it1 = arg1seq_tmp.begin();

    while(it3 != arg3seq.end() && it1 != arg1seq_tmp.end())
    {
        switch(nid_cmp_effective((*it3).cells[0].get_node(), *it1))
        {
        case 0: case -2:
            {
                node = copy_to_temp((*it3).cells[0].get_node());
                xptr indir=nodeGetIndirection(node);
                arg2seq.set(indir,(*it3).cells[1].get_xs_integer());
                ++it3;
            }
            break;
        case 1:
            ++it1;
            break;
        case 2:
            ++it1;
            break;
        case -1:
            ++it3;
            break;
        }
    }
#ifdef SE_ENABLE_TRIGGERS
    apply_per_statement_triggers(&arg1seq, false, NULL, false, TRIGGER_BEFORE, TRIGGER_REPLACE_EVENT);
#endif

    arg3seq.clear();
    xptr_sequence::iterator it  = arg1seq.begin();
    xptr_sequence::iterator sit = arg2seq.begin();
    int ctr=0;
    do
    {
        tuple tup(2);
        /* arg3seq will contain pairs: node -> int, namely
        * node to be replaced -> place in sequence of nodes to replace with */
        tup.copy(tuple_cell::node(indirectionDereferenceCP(*it)),tuple_cell((int64_t)ctr));
        arg3seq.add(tup);
        /* XNULL separates nodes in arg2seq (nodes replace with) per each
        * node in arg1seq (nodes to be replaced) */
        while(*sit!=XNULL)
        {
            sit++;
            ctr++;
        }
        sit++;
        ctr++;
        it++;
    } while (it != arg1seq.end());

    arg3seq.sort();
    it3=arg3seq.begin();
    descript_sequence arg4seq(2);
    do
    {
        node=(*it3).cells[0].get_node();
        tuple t=(*it3);
        t.cells[0].set_safenode(node);
        ++it3;
        arg4seq.add(t);

    } while (it3!=arg3seq.end());

    /* Deleting, inserting new nodes */
    it3 = arg4seq.end();
    do
    {
        --it3;
        node = old_node = (*it3).cells[0].get_safenode();
        int pos=(*it3).cells[1].get_xs_integer();
        sit=arg2seq.begin()+pos;
        CHECKP(node);
        xptr leftn=nodeGetLeftSibling(old_node);
        xptr rightn=nodeGetRightSibling(old_node);
        xptr par_ind= nodeGetParentIndirection(old_node);
        bool a_m=is_node_attribute(node);
        bool d_m=a_m||is_node_text(node);

#ifdef SE_ENABLE_TRIGGERS
        CHECKP(old_node);
        scm_node = getSchemaPointer(old_node);
        parent=  nodeGetParent(old_node);
        CHECKP(old_node);
        tmp_node = prepare_old_node(old_node, scm_node, TRIGGER_REPLACE_EVENT);

        /* Before-for-each-node triggers (cycle for all inserted nodes) */
        xptr_sequence::iterator tr_it=sit;
        while(*tr_it!=XNULL)
        {
            node_child=*tr_it;
            parent=indirectionDereferenceCP(par_ind);
            if(apply_per_node_triggers(indirectionDereferenceCP(node_child), old_node, parent, scm_node, TRIGGER_BEFORE, TRIGGER_REPLACE_EVENT) == XNULL)
                goto next_replacement;
            tr_it++;
        }
#endif

        //pre_deletion
        if (d_m)
        {
            delete_node(old_node);
        }
        //1.inserting attributes from sequence
        while(*sit != XNULL)
        {
            node_child = *sit;
            if (is_node_attribute(indirectionDereferenceCP(node_child)))
            {
                parent = indirectionDereferenceCP(par_ind);
                attr_node=deep_copy_node(XNULL, XNULL, parent, indirectionDereferenceCP(node_child), is_node_persistent(node_child) ? NULL : &ins_swiz, true);
#ifdef SE_ENABLE_TRIGGERS
                apply_per_node_triggers(attr_node, tmp_node, parent, scm_node, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
            }
            sit++;
        }
        //2. finding place of insertion
        if (a_m)
        {
            node= getFirstChildNode(indirectionDereferenceCP(par_ind));
            if (node!=XNULL)
            {
                CHECKP(node);
                if (is_node_element(node))
                {
                    rightn=node;
                    node=XNULL;
                }
                else
                {
                    rightn=XNULL;
                }
            }
        }
        else
        {
            if (d_m)
            {
                if (rightn==XNULL)
                    node=leftn;
                else
                    node=XNULL;
            }
        }
        //3.main insert cycle
        sit = arg2seq.begin() + pos;
        while(*sit != XNULL)
        {
            node_child = *sit;
            if (!is_node_attribute(indirectionDereferenceCP(node_child)))
            {
                parent = indirectionDereferenceCP(par_ind);
                node = deep_copy_node(node, rightn, parent, indirectionDereferenceCP(node_child), is_node_persistent(node_child) ? NULL : &ins_swiz, true);
#ifdef SE_ENABLE_TRIGGERS
                apply_per_node_triggers(node, tmp_node, indirectionDereferenceCP(par_ind), scm_node, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
            }
            sit++;
        }
        //post_deletion
        if (!d_m)
        {
            del_node = (*it3).cells[0].get_safenode();
            CHECKP(del_node);
            delete_node(del_node);
        }
next_replacement:;
    }
    while (it3!=arg4seq.begin());

    if (ins_swiz!=NULL)
    {
        delete ins_swiz;
    }
#ifdef SE_ENABLE_FTSEARCH
    execute_modifications();
#endif
#ifdef SE_ENABLE_TRIGGERS
    apply_per_statement_triggers(NULL, false, NULL, false, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
}
<commit_msg>CHECKP fixed in replace + small refactoring<commit_after>/*
 * File:  other_updates.cpp
 * Copyright (C) 2004 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "common/sedna.h"

#include "tr/updates/updates.h"
#include "tr/executor/base/xptr_sequence.h"
#include "tr/mo/mo.h"
#include "tr/auth/auc.h"
#include "tr/locks/locks.h"

#ifdef SE_ENABLE_TRIGGERS
#include "tr/triggers/triggers.h"
#endif

#include "tr/structures/nodeutils.h"
#include "tr/structures/textcptr.h"

void replace(PPOpIn arg)
{
    xptr node, tmp_node, attr_node;
    schema_node_xptr scm_node;
    tuple t(arg.ts);

    xptr_sequence arg1seq;        // Indirection of nodes which are going to be replaced
    xptr_sequence arg1seq_tmp;    // Nodes which are going to be replaced
    xptr_sequence arg2seq;        // Nodes to replace with (both persistent and temp)

    /* Persistent nodes to replace with (+ theirs position in arg2seq) */
    descript_sequence arg3seq(2);

    upd_ns_map* ins_swiz = NULL;
    bool is_node_updated = true;

    /*
     * Fill up sequences with nodes to update and update with,
     * child (arg) returns the following sequence of items:
     * 1. node to be replaced (1)
     * 2. nodes to replace with (2)
     * 3. special tuple which contains separator value (3)
     */
    arg.op->next(t);

    while (!t.is_eos())
    {
        if (t.cells[0].is_node())
        {
            node = t.cells[0].get_node();
            CHECKP(node);
            /*
             * In (1) case node must be persistent (is_node_updated is true)
             * In (2) case it can be temporary
             * In both cases document nodes are not allowed
             */
            if ((!is_node_updated || is_node_persistent(node)) && !is_node_document(node))
            {
                xptr indir = nodeGetIndirection(node);

                if (is_node_updated)
                {
                    /* Case (1) - fill up sequence with nodes to be replaced */
                    is_node_updated=false;
                    /* Next nodes from arg are case (2) nodes, so we can use shared lock */
                    local_lock_mrg->lock(lm_s);
                    arg1seq.add(indir);
                    arg1seq_tmp.add(node);
                }
                else
                {
                    /* Case (2) - fill up sequence with nodes to replace with */
                    if (is_node_persistent(node))
                    {
                        tuple tup(2);
                        tup.copy(tuple_cell::node(node),tuple_cell((int64_t)(arg2seq.size())));
                        arg3seq.add(tup);
                    }
                    arg2seq.add(indir);
                }
            }
#ifndef IGNORE_UPDATE_ERRORS
            else
            {
                throw USER_EXCEPTION(SE2020);
            }
#endif
        }
        else
        {
            /* Must be separator in this case (3) */
            if (t.cells[0].get_atomic_type() == se_separator)
            {
                arg2seq.add(XNULL);
                is_node_updated=true;
                /* Next nodes from arg are case (1) node, so we can use shared lock */
                local_lock_mrg->lock(lm_x);
            }
#ifndef IGNORE_UPDATE_ERRORS
            else throw USER_EXCEPTION(SE2021);
#endif
        }

        arg.op->next(t);
    }

    /* Nothing to do in this case */
    if (arg1seq.size()<=0) return;

    /* Checking authorization */
    if (is_auth_check_needed(REPLACE_STATEMENT))
        auth_for_update(&arg1seq, REPLACE_STATEMENT, false);

    /* Find all common nodes in agr3seq (nodes to replace with) and
     * arg1seq_tmp (nodes to be replaced). Make a copy of all such nodes. */
    arg1seq_tmp.sort();
    arg3seq.sort();
    descript_sequence::iterator it3 = arg3seq.begin();
    xptr_sequence::iterator     it1 = arg1seq_tmp.begin();

    while(it3 != arg3seq.end() && it1 != arg1seq_tmp.end())
    {
        switch(nid_cmp_effective((*it3).cells[0].get_node(), *it1))
        {
        case 0: case -2:
            {
                node = copy_to_temp((*it3).cells[0].get_node());
                xptr indir=nodeGetIndirection(node);
                arg2seq.set(indir,(*it3).cells[1].get_xs_integer());
                ++it3;
            }
            break;
        case 1:
            ++it1;
            break;
        case 2:
            ++it1;
            break;
        case -1:
            ++it3;
            break;
        }
    }
#ifdef SE_ENABLE_TRIGGERS
    apply_per_statement_triggers(&arg1seq, false, NULL, false, TRIGGER_BEFORE, TRIGGER_REPLACE_EVENT);
#endif

    arg3seq.clear();
    xptr_sequence::iterator it  = arg1seq.begin();
    xptr_sequence::iterator sit = arg2seq.begin();
    int ctr=0;
    do
    {
        tuple tup(2);
        /* arg3seq will contain pairs: node -> int, namely
        * node to be replaced -> place in sequence of nodes to replace with */
        tup.copy(tuple_cell::node(indirectionDereferenceCP(*it)),tuple_cell((int64_t)ctr));
        arg3seq.add(tup);
        /* XNULL separates nodes in arg2seq (nodes replace with) per each
        * node in arg1seq (nodes to be replaced) */
        while(*sit!=XNULL)
        {
            sit++;
            ctr++;
        }
        sit++;
        ctr++;
        it++;
    } while (it != arg1seq.end());

    arg3seq.sort();
    it3=arg3seq.begin();
    descript_sequence arg4seq(2);
    do
    {
        node = (*it3).cells[0].get_node();
        tuple t = (*it3);
        t.cells[0].set_safenode(node);
        ++it3;
        arg4seq.add(t);

    } while (it3!=arg3seq.end());

    /* Deleting, inserting new nodes */
    it3 = arg4seq.end();
    do
    {
        --it3;
        node = (*it3).cells[0].get_safenode();
        int pos = (*it3).cells[1].get_xs_integer();
        sit = arg2seq.begin() + pos;
        CHECKP(node);
        xptr leftn   = nodeGetLeftSibling(node);
        xptr rightn  = nodeGetRightSibling(node);
        xptr par_ind = nodeGetParentIndirection(node);
        bool a_m = is_node_attribute(node);
        bool d_m = a_m || is_node_text(node);

#ifdef SE_ENABLE_TRIGGERS
        scm_node = getSchemaPointer(node);
        tmp_node = prepare_old_node(node, scm_node, TRIGGER_REPLACE_EVENT);

        /* Before-for-each-node triggers (cycle for all inserted nodes) */
        xptr_sequence::iterator tr_it = sit;
        while(*tr_it != XNULL)
        {
            if(apply_per_node_triggers(indirectionDereferenceCP(*tr_it),
                                       node,
                                       indirectionDereferenceCP(par_ind),
                                       scm_node,
                                       TRIGGER_BEFORE,
                                       TRIGGER_REPLACE_EVENT) == XNULL)
            {
                goto next_replacement;
            }
            tr_it++;
        }
#endif /* SE_ENABLE_TRIGGERS */

        //pre_deletion
        if (d_m)
        {
            delete_node(node);
        }
        //1.inserting attributes from sequence
        while(*sit != XNULL)
        {
            xptr node_child = indirectionDereferenceCP(*sit);
            if (is_node_attribute(node_child))
            {
                attr_node = deep_copy_node(XNULL, XNULL, indirectionDereferenceCP(par_ind), node_child, is_node_persistent(node_child) ? NULL : &ins_swiz, true);
#ifdef SE_ENABLE_TRIGGERS
                apply_per_node_triggers(attr_node, tmp_node, indirectionDereferenceCP(par_ind), scm_node, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
            }
            sit++;
        }
        //2. finding place of insertion
        if (a_m)
        {
            node = getFirstChildNode(indirectionDereferenceCP(par_ind));
            if (node != XNULL)
            {
                CHECKP(node);
                if (is_node_element(node))
                {
                    rightn=node;
                    node=XNULL;
                }
                else
                {
                    rightn=XNULL;
                }
            }
        }
        else
        {
            if (d_m)
            {
                if (rightn==XNULL)
                    node=leftn;
                else
                    node=XNULL;
            }
        }
        //3.main insert cycle
        sit = arg2seq.begin() + pos;
        while(*sit != XNULL)
        {
            xptr node_child = indirectionDereferenceCP(*sit);
            CHECKP(node_child);
            if (!is_node_attribute(node_child))
            {
                node = deep_copy_node(node, rightn, indirectionDereferenceCP(par_ind), node_child, is_node_persistent(node_child) ? NULL : &ins_swiz, true);
#ifdef SE_ENABLE_TRIGGERS
                apply_per_node_triggers(node, tmp_node, indirectionDereferenceCP(par_ind), scm_node, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
            }
            sit++;
        }
        //post_deletion
        if (!d_m)
        {
            xptr del_node = (*it3).cells[0].get_safenode();
            delete_node(del_node);
        }
next_replacement:;
    }
    while (it3 != arg4seq.begin());

    if (ins_swiz != NULL)
    {
        delete ins_swiz;
    }
#ifdef SE_ENABLE_FTSEARCH
    execute_modifications();
#endif
#ifdef SE_ENABLE_TRIGGERS
    apply_per_statement_triggers(NULL, false, NULL, false, TRIGGER_AFTER, TRIGGER_REPLACE_EVENT);
#endif
}
<|endoftext|>


<commit_before>//
//  conflict.cpp
//  Parse
//
//  Created by Andrew Hunter on 04/06/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "conflict.h"

using namespace std;
using namespace contextfree;
using namespace lr;

/// \brief Creates a new conflict object (describing a non-conflict)
conflict::conflict(int stateId, const item_container& token)
: m_StateId(stateId)
, m_Token(token) {
}

/// \brief Copy constructor
conflict::conflict(const conflict& copyFrom)
: m_StateId(copyFrom.m_StateId)
, m_Token(copyFrom.m_Token)
, m_Shift(copyFrom.m_Shift)
, m_Reduce(copyFrom.m_Reduce) {
}

/// \brief Destroys this conflict object
conflict::~conflict() { }

/// \brief Clones this conflict
conflict* conflict::clone() const {
    return new conflict(*this);
}

/// \brief Returns true if conflict a is less than conflict b
bool conflict::compare(const conflict* a, const conflict* b) {
    if (a == b) return false;
    if (!a) return true;
    if (!b) return false;

    return (*a) < (*b);
}

/// \brief Orders this conflict relative to another
bool conflict::operator<(const conflict& compareTo) const {
    if (m_StateId < compareTo.m_StateId) return true;
    if (m_StateId > compareTo.m_StateId) return false;

    if (m_Token < compareTo.m_Token) return true;
    if (m_Token > compareTo.m_Token) return false;

    if (m_Shift < compareTo.m_Shift) return true;
    if (m_Shift > compareTo.m_Shift) return false;

    if (m_Reduce < compareTo.m_Reduce) return true;

    return false;
}

/// \brief Adds an LR(0) item that will be followed if the token is shifted
void conflict::add_shift_item(const lr0_item_container& item) {
    m_Shift.insert(item);
}

/// \brief Adds an LR(0) item that will be reduced if the token is in the lookahead
///
/// This returns an item that the caller can add the set of reduce states for this item
conflict::possible_reduce_states& conflict::add_reduce_item(const lr0_item_container& item) {
    return m_Reduce[item];
}

/// \brief Adds the conflicts found in a single state of the specified LALR builder to the given target list
static void find_conflicts(const lalr_builder& builder, int stateId, conflict_list& target) {
    // Get the actions in this state
    const lr_action_set& actions = builder.actions_for_state(stateId);

    // Run through these actions, and find places where there are conflicts (two actions for a single symbol)
    typedef map<item_container, lr_action_set> items_to_actions;
    items_to_actions actionsForItem;

    for (lr_action_set::const_iterator nextAction = actions.begin(); nextAction != actions.end(); nextAction++) {
        // Ignore actions that don't cause conflicts
        bool ignore;
        switch ((*nextAction)->type()) {
            case lr_action::act_goto:
            case lr_action::act_ignore:
            case lr_action::act_accept:
                ignore = true;
                break;

            default:
                ignore = false;
                break;
        }
        if (ignore) continue;

        // Add this as an action for this item
        actionsForItem[(*nextAction)->item()].insert(*nextAction);
    }

    // Generate conflicts for any item with multiple actions
    for (items_to_actions::iterator nextItem = actionsForItem.begin(); nextItem != actionsForItem.end(); nextItem++) {
        // Ignore items with just one action (or no actions, if that's ever possible)
        if (nextItem->second.size() < 2) continue;

        // Ignore items if all but one of the items are 'weak'
        int numWeak = 0;
        for (lr_action_set::const_iterator nextAction = nextItem->second.begin(); nextAction != nextItem->second.end(); nextAction++) {
            switch ((*nextAction)->type()) {
                case lr_action::act_weakreduce:
                case lr_action::act_ignore:
                    numWeak++;
                    break;

                default:
                    break;
            }
        }

        if (nextItem->second.size() - numWeak < 2) continue;

        // Create a new conflict for this action
        const item_container&   conflictToken = *nextItem->first;
        conflict_container      newConf(new conflict(stateId, conflictToken), true);

        // Fetch the items in this state
        const lalr_state& thisState = *builder.machine().state_with_id(stateId);

        // Get the closure of this state
        lr1_item_set closure;
        builder.generate_closure(thisState, closure);

        // Describe the actions resulting in this conflict by going through the items in the closure of the state
        const grammar*    gram = &builder.gram();

        // Iterate through the closure to get the items that can be shifted as part of this conflict
        for (lr1_item_set::const_iterator nextItem = closure.begin(); nextItem != closure.end(); nextItem++) {
            if (!(*nextItem)->at_end()) {
                // This item will result in a shift: add it to the list if it can shift our item
                const item_set& firstItems = gram->first((*nextItem)->rule()->items()[(*nextItem)->offset()]);

                if (firstItems.find(conflictToken) != firstItems.end()) {
                    // This item can result in a shift of the specified token
                    newConf->add_shift_item(**nextItem);
                }
            }
        }

        // Iterate through the closure to find the items that can be reduced as part of this conflict
        for (lr1_item_set::const_iterator nextItem = closure.begin(); nextItem != closure.end(); nextItem++) {
            if ((*nextItem)->at_end()) {
                // This item will result in a reduction, depending on its lookahead
                const lr1_item::lookahead_set& la = (*nextItem)->lookahead();

                if (la.find(conflictToken) != la.end()) {
                    // The conflicted token is in the lookahead: add this to the conflict list
                    conflict::possible_reduce_states& reduceTo = newConf->add_reduce_item(**nextItem);

                    // TODO: fill in the set of items that this can reduce to
                }
            }
        }

        // Add the new conflict to the list
        target.push_back(newConf);
    }
}

/// \brief Adds the conflicts found in the specified LALR builder object to the passed in list
void conflict::find_conflicts(const lalr_builder& builder, conflict_list& target) {
    // Iterate through the states in the builder
    for (int stateId=0; stateId < builder.count_states(); stateId++) {
        ::find_conflicts(builder, stateId, target);
    }
}

<commit_msg>Added a TODO note about some stuff that can go wrong<commit_after>//
//  conflict.cpp
//  Parse
//
//  Created by Andrew Hunter on 04/06/2011.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "conflict.h"

using namespace std;
using namespace contextfree;
using namespace lr;

/// \brief Creates a new conflict object (describing a non-conflict)
conflict::conflict(int stateId, const item_container& token)
: m_StateId(stateId)
, m_Token(token) {
}

/// \brief Copy constructor
conflict::conflict(const conflict& copyFrom)
: m_StateId(copyFrom.m_StateId)
, m_Token(copyFrom.m_Token)
, m_Shift(copyFrom.m_Shift)
, m_Reduce(copyFrom.m_Reduce) {
}

/// \brief Destroys this conflict object
conflict::~conflict() { }

/// \brief Clones this conflict
conflict* conflict::clone() const {
    return new conflict(*this);
}

/// \brief Returns true if conflict a is less than conflict b
bool conflict::compare(const conflict* a, const conflict* b) {
    if (a == b) return false;
    if (!a) return true;
    if (!b) return false;

    return (*a) < (*b);
}

/// \brief Orders this conflict relative to another
bool conflict::operator<(const conflict& compareTo) const {
    if (m_StateId < compareTo.m_StateId) return true;
    if (m_StateId > compareTo.m_StateId) return false;

    if (m_Token < compareTo.m_Token) return true;
    if (m_Token > compareTo.m_Token) return false;

    if (m_Shift < compareTo.m_Shift) return true;
    if (m_Shift > compareTo.m_Shift) return false;

    if (m_Reduce < compareTo.m_Reduce) return true;

    return false;
}

/// \brief Adds an LR(0) item that will be followed if the token is shifted
void conflict::add_shift_item(const lr0_item_container& item) {
    m_Shift.insert(item);
}

/// \brief Adds an LR(0) item that will be reduced if the token is in the lookahead
///
/// This returns an item that the caller can add the set of reduce states for this item
conflict::possible_reduce_states& conflict::add_reduce_item(const lr0_item_container& item) {
    return m_Reduce[item];
}

/// \brief Adds the conflicts found in a single state of the specified LALR builder to the given target list
static void find_conflicts(const lalr_builder& builder, int stateId, conflict_list& target) {
    // Get the actions in this state
    const lr_action_set& actions = builder.actions_for_state(stateId);

    // Run through these actions, and find places where there are conflicts (two actions for a single symbol)
    typedef map<item_container, lr_action_set> items_to_actions;
    items_to_actions actionsForItem;

    for (lr_action_set::const_iterator nextAction = actions.begin(); nextAction != actions.end(); nextAction++) {
        // Ignore actions that don't cause conflicts
        bool ignore;
        switch ((*nextAction)->type()) {
            case lr_action::act_goto:
            case lr_action::act_ignore:
            case lr_action::act_accept:
                ignore = true;
                break;

            default:
                ignore = false;
                break;
        }
        if (ignore) continue;

        // Add this as an action for this item
        actionsForItem[(*nextAction)->item()].insert(*nextAction);
    }

    // Generate conflicts for any item with multiple actions
    for (items_to_actions::iterator nextItem = actionsForItem.begin(); nextItem != actionsForItem.end(); nextItem++) {
        // Ignore items with just one action (or no actions, if that's ever possible)
        if (nextItem->second.size() < 2) continue;

        // Ignore items if all but one of the items are 'weak'
        int numWeak = 0;
        for (lr_action_set::const_iterator nextAction = nextItem->second.begin(); nextAction != nextItem->second.end(); nextAction++) {
            switch ((*nextAction)->type()) {
                case lr_action::act_weakreduce:
                case lr_action::act_ignore:
                    numWeak++;
                    break;

                default:
                    break;
            }
        }

        if (nextItem->second.size() - numWeak < 2) continue;

        // Create a new conflict for this action
        const item_container&   conflictToken = *nextItem->first;
        conflict_container      newConf(new conflict(stateId, conflictToken), true);

        // Fetch the items in this state
        const lalr_state& thisState = *builder.machine().state_with_id(stateId);

        // Get the closure of this state
        lr1_item_set closure;
        builder.generate_closure(thisState, closure);

        // Describe the actions resulting in this conflict by going through the items in the closure of the state
        const grammar*    gram = &builder.gram();

        // Iterate through the closure to get the items that can be shifted as part of this conflict
        for (lr1_item_set::const_iterator nextItem = closure.begin(); nextItem != closure.end(); nextItem++) {
            if (!(*nextItem)->at_end()) {
                // This item will result in a shift: add it to the list if it can shift our item
                const item_set& firstItems = gram->first((*nextItem)->rule()->items()[(*nextItem)->offset()]);

                if (firstItems.find(conflictToken) != firstItems.end()) {
                    // This item can result in a shift of the specified token
                    newConf->add_shift_item(**nextItem);
                }
            }
        }

        // Iterate through the closure to find the items that can be reduced as part of this conflict
        for (lr1_item_set::const_iterator nextItem = closure.begin(); nextItem != closure.end(); nextItem++) {
            if ((*nextItem)->at_end()) {
                // This item will result in a reduction, depending on its lookahead
                const lr1_item::lookahead_set& la = (*nextItem)->lookahead();

                if (la.find(conflictToken) != la.end()) {
                    // The conflicted token is in the lookahead: add this to the conflict list
                    conflict::possible_reduce_states& reduceTo = newConf->add_reduce_item(**nextItem);

                    // TODO: fill in the set of items that this can reduce to
                    // TODO: if the reduction is not in a kernel item (which probably means that we've got an empty production), then we need to be able to trace these as well.
                }
            }
        }

        // Add the new conflict to the list
        target.push_back(newConf);
    }
}

/// \brief Adds the conflicts found in the specified LALR builder object to the passed in list
void conflict::find_conflicts(const lalr_builder& builder, conflict_list& target) {
    // Iterate through the states in the builder
    for (int stateId=0; stateId < builder.count_states(); stateId++) {
        ::find_conflicts(builder, stateId, target);
    }
}

<|endoftext|>


<commit_before>/* gdnet_peer.cpp */

#include "gdnet_peer.h"

GDNetPeer::GDNetPeer(GDNetHost* host, ENetPeer* peer) : _host(host), _peer(peer) {
	_host->reference();
}

GDNetPeer::~GDNetPeer() {
	_host->unreference();
}

int GDNetPeer::get_peer_id() {
	ERR_FAIL_COND_V(_host->_host == NULL, -1);
	return (int)(_peer - _host->_host->peers);
}

Ref<GDNetAddress> GDNetPeer::get_address() {
	Ref<GDNetAddress> address = memnew(GDNetAddress);
	address->set_port(_peer->address.port);

	char ip[64];
	enet_address_get_host_ip(&_peer->address, ip, 64);
	address->set_host(ip);

	return address;
}

int GDNetPeer::get_avg_rtt() {
	ERR_FAIL_COND_V(_host->_host == NULL, -1);
	return _peer->roundTripTime;
}

void GDNetPeer::ping() {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_ping(_peer);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::reset() {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_reset(_peer);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect_later(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect_later(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect_now(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect_now(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::send_packet(const ByteArray& packet, int channel_id, int type) {
	ERR_FAIL_COND(_host->_host == NULL);

	GDNetMessage* message = memnew(GDNetMessage((GDNetMessage::Type)type));
	message->set_peer_id(get_peer_id());
	message->set_channel_id(channel_id);
	message->set_packet(packet);
	_host->_message_queue.push(message);
}

void GDNetPeer::send_var(const Variant& var, int channel_id, int type) {
	ERR_FAIL_COND(_host->_host == NULL);

	int len;

	Error err = encode_variant(var, NULL, len);

	ERR_FAIL_COND(err != OK || len == 0);

	GDNetMessage* message = memnew(GDNetMessage((GDNetMessage::Type)type));
	message->set_peer_id(get_peer_id());
	message->set_channel_id(channel_id);

	ByteArray packet;
	packet.resize(len);

	ByteArray::Write w = packet.write();
	err = encode_variant(var, w.ptr(), len);

	ERR_FAIL_COND(err != OK);

	message->set_packet(packet);

	_host->_message_queue.push(message);
}

void GDNetPeer::set_timeout(int limit, int min_timeout, int max_timeout) {
	enet_peer_timeout(_peer, limit, min_timeout, max_timeout);
}

void GDNetPeer::_bind_methods() {
	ObjectTypeDB::bind_method("get_peer_id", &GDNetPeer::get_peer_id);
	ObjectTypeDB::bind_method("get_address", &GDNetPeer::get_address);
	ObjectTypeDB::bind_method("get_avg_rtt", &GDNetPeer::get_avg_rtt);
	ObjectTypeDB::bind_method("ping", &GDNetPeer::ping);
	ObjectTypeDB::bind_method("reset", &GDNetPeer::reset);
	ObjectTypeDB::bind_method("disconnect", &GDNetPeer::disconnect,DEFVAL(0));
	ObjectTypeDB::bind_method("disconnect_later", &GDNetPeer::disconnect_later,DEFVAL(0));
	ObjectTypeDB::bind_method("disconnect_now", &GDNetPeer::disconnect_now,DEFVAL(0));
	ObjectTypeDB::bind_method("send_packet", &GDNetPeer::send_packet,DEFVAL(0),DEFVAL(GDNetMessage::UNSEQUENCED));
	ObjectTypeDB::bind_method("send_var", &GDNetPeer::send_var,DEFVAL(0),DEFVAL(GDNetMessage::UNSEQUENCED));
	ObjectTypeDB::bind_method("set_timeout", &GDNetPeer::set_timeout);
}
<commit_msg>Added locking for set_timeout<commit_after>/* gdnet_peer.cpp */

#include "gdnet_peer.h"

GDNetPeer::GDNetPeer(GDNetHost* host, ENetPeer* peer) : _host(host), _peer(peer) {
	_host->reference();
}

GDNetPeer::~GDNetPeer() {
	_host->unreference();
}

int GDNetPeer::get_peer_id() {
	ERR_FAIL_COND_V(_host->_host == NULL, -1);
	return (int)(_peer - _host->_host->peers);
}

Ref<GDNetAddress> GDNetPeer::get_address() {
	Ref<GDNetAddress> address = memnew(GDNetAddress);
	address->set_port(_peer->address.port);

	char ip[64];
	enet_address_get_host_ip(&_peer->address, ip, 64);
	address->set_host(ip);

	return address;
}

int GDNetPeer::get_avg_rtt() {
	ERR_FAIL_COND_V(_host->_host == NULL, -1);
	return _peer->roundTripTime;
}

void GDNetPeer::ping() {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_ping(_peer);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::reset() {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_reset(_peer);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect_later(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect_later(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::disconnect_now(int data) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_disconnect_now(_peer, data);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::send_packet(const ByteArray& packet, int channel_id, int type) {
	ERR_FAIL_COND(_host->_host == NULL);

	GDNetMessage* message = memnew(GDNetMessage((GDNetMessage::Type)type));
	message->set_peer_id(get_peer_id());
	message->set_channel_id(channel_id);
	message->set_packet(packet);
	_host->_message_queue.push(message);
}

void GDNetPeer::send_var(const Variant& var, int channel_id, int type) {
	ERR_FAIL_COND(_host->_host == NULL);

	int len;

	Error err = encode_variant(var, NULL, len);

	ERR_FAIL_COND(err != OK || len == 0);

	GDNetMessage* message = memnew(GDNetMessage((GDNetMessage::Type)type));
	message->set_peer_id(get_peer_id());
	message->set_channel_id(channel_id);

	ByteArray packet;
	packet.resize(len);

	ByteArray::Write w = packet.write();
	err = encode_variant(var, w.ptr(), len);

	ERR_FAIL_COND(err != OK);

	message->set_packet(packet);

	_host->_message_queue.push(message);
}

void GDNetPeer::set_timeout(int limit, int min_timeout, int max_timeout) {
	ERR_FAIL_COND(_host->_host == NULL);

	while (true) {
		if (_host->_mutex->try_lock() == 0) {
			enet_peer_timeout(_peer, limit, min_timeout, max_timeout);
			_host->_mutex->unlock();
			break;
		}
	}
}

void GDNetPeer::_bind_methods() {
	ObjectTypeDB::bind_method("get_peer_id", &GDNetPeer::get_peer_id);
	ObjectTypeDB::bind_method("get_address", &GDNetPeer::get_address);
	ObjectTypeDB::bind_method("get_avg_rtt", &GDNetPeer::get_avg_rtt);
	ObjectTypeDB::bind_method("ping", &GDNetPeer::ping);
	ObjectTypeDB::bind_method("reset", &GDNetPeer::reset);
	ObjectTypeDB::bind_method("disconnect", &GDNetPeer::disconnect,DEFVAL(0));
	ObjectTypeDB::bind_method("disconnect_later", &GDNetPeer::disconnect_later,DEFVAL(0));
	ObjectTypeDB::bind_method("disconnect_now", &GDNetPeer::disconnect_now,DEFVAL(0));
	ObjectTypeDB::bind_method("send_packet", &GDNetPeer::send_packet,DEFVAL(0),DEFVAL(GDNetMessage::UNSEQUENCED));
	ObjectTypeDB::bind_method("send_var", &GDNetPeer::send_var,DEFVAL(0),DEFVAL(GDNetMessage::UNSEQUENCED));
	ObjectTypeDB::bind_method("set_timeout", &GDNetPeer::set_timeout);
}
<|endoftext|>