<commit_before>#ifndef ARABICA_XPATHIC_XPATH_STEP_H
#define ARABICA_XPATHIC_XPATH_STEP_H

#include <DOM/Document.h>
#include <algorithm>
#include "xpath_object.hpp"
#include "xpath_value.hpp"
#include "xpath_axis_enumerator.hpp"
#include "xpath_node_test.hpp"
#include "xpath_ast.hpp"
#include "xpath_ast_ids.hpp"
#include "xpath_namespace_context.hpp"
#include "xpath_compile_context.hpp"

namespace Arabica
{
namespace XPath
{
namespace impl
{

template<class string_type, class string_adaptor>
class StepExpression : public XPathExpression<string_type, string_adaptor>
{
public:
  StepExpression() { }
  StepExpression(const std::vector<XPathExpression<string_type, string_adaptor> *>& predicates) : predicates_(predicates) { }

  virtual ~StepExpression()
  { 
    for(typename std::vector<XPathExpression<string_type, string_adaptor>*>::iterator p = predicates_.begin(), e = predicates_.end(); p != e; ++p)
      delete *p;
  } // ~StepExpression

  virtual XPathValuePtr<string_type> evaluate(const DOM::Node<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const = 0;
  virtual XPathValuePtr<string_type> evaluate(NodeSet<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const = 0;

  bool has_predicates() const { return !predicates_.empty(); }

protected:
  NodeSet<string_type> applyPredicates(NodeSet<string_type>& nodes, const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    for(typename std::vector<XPathExpression<string_type, string_adaptor>*>::const_iterator p = predicates_.begin(), e = predicates_.end();
        (p != e) && (!nodes.empty()); ++p)
      nodes = applyPredicate(nodes, *p, parentContext);
    return nodes;
  } // applyPredicates

private:
  NodeSet<string_type> applyPredicate(NodeSet<string_type>& nodes, 
                                      XPathExpression<string_type, string_adaptor>* predicate, 
                                      const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    ExecutionContext<string_type, string_adaptor> executionContext(nodes.size(), parentContext);
    NodeSet<string_type> results(nodes.forward());
    unsigned int position = 1;
    for(typename NodeSet<string_type>::iterator i = nodes.begin(); i != nodes.end(); ++i, ++position)
    {
      executionContext.setPosition(position);
      XPathValuePtr<string_type> v = predicate->evaluate(*i, executionContext);

      if((v->type() == NUMBER) && (position != v->asNumber()))
        continue;
      if(v->asBool() == false)
        continue;

      results.push_back(*i);
    } // for ...
    return results;
  } // applyPredicate
  
  std::vector<XPathExpression<string_type, string_adaptor>*> predicates_;
}; // StepExpression

template<class string_type, class string_adaptor>
class TestStepExpression : public StepExpression<string_type, string_adaptor>
{
  typedef StepExpression<string_type, string_adaptor> baseT;
public:
  TestStepExpression(Axis axis, NodeTest<string_type>* test) :
      StepExpression<string_type, string_adaptor>(),
      axis_(axis),
      test_(test)
  {
  } // TestStepExpression

  TestStepExpression(Axis axis, NodeTest<string_type>* test, 
                     const std::vector<XPathExpression<string_type, string_adaptor>*>& predicates) :
      StepExpression<string_type, string_adaptor>(predicates),
      axis_(axis),
      test_(test)
  {
  } // TestStepExpression

  virtual ~TestStepExpression()
  {
    delete test_;
  } // StepExpression

  virtual XPathValuePtr<string_type> evaluate(const DOM::Node<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    NodeSet<string_type> nodes;
    enumerateOver(context, nodes, executionContext);
    return XPathValuePtr<string_type>(new NodeSetValue<string_type, string_adaptor>(nodes));
  } // evaluate

  virtual XPathValuePtr<string_type> evaluate(NodeSet<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    NodeSet<string_type> nodes;
    for(typename NodeSet<string_type>::iterator n = context.begin(); n != context.end(); ++n)
      enumerateOver(*n, nodes, executionContext);
    return XPathValuePtr<string_type>(new NodeSetValue<string_type, string_adaptor>(nodes));
  } // evaluate

private:
  void enumerateOver(const DOM::Node<string_type>& context, 
                     NodeSet<string_type>& results, 
                     const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    AxisEnumerator<string_type, string_adaptor> enumerator(context, axis_);
    NodeSet<string_type> intermediate(enumerator.forward());
    NodeSet<string_type>& d = (!baseT::has_predicates()) ? results : intermediate;
    while(*enumerator != 0)
    {
      // if test
      DOM::Node<string_type> node = *enumerator;
      if((*test_)(node))
        d.push_back(node);
      ++enumerator;
    } // while ...
    
    if(!baseT::has_predicates())
    {
      results.forward(enumerator.forward());
      return;
    } // if ...

    intermediate = baseT::applyPredicates(intermediate, parentContext);

    results.swap(intermediate);
  } // enumerateOver

  Axis axis_;
  NodeTest<string_type>* test_;
}; // class TestStepExpression

template<class string_type, class string_adaptor>
class ExprStepExpression : public StepExpression<string_type, string_adaptor>
{
  typedef StepExpression<string_type, string_adaptor> baseT;
public:
  ExprStepExpression(XPathExpression<string_type, string_adaptor>* expr, 
                     const std::vector<XPathExpression<string_type, string_adaptor>*>& predicates) :
      StepExpression<string_type, string_adaptor>(predicates),
      expr_(expr)
  {
  } // ExprStepExpression

  virtual ~ExprStepExpression()
  {
    delete expr_;<commit_msg>Fixed for predicate evaluation bug see http://www.jezuk.co.uk/cgi-bin/view/arabica/news?id=2883<commit_after>#ifndef ARABICA_XPATHIC_XPATH_STEP_H
#define ARABICA_XPATHIC_XPATH_STEP_H

#include <DOM/Document.h>
#include <algorithm>
#include "xpath_object.hpp"
#include "xpath_value.hpp"
#include "xpath_axis_enumerator.hpp"
#include "xpath_node_test.hpp"
#include "xpath_ast.hpp"
#include "xpath_ast_ids.hpp"
#include "xpath_namespace_context.hpp"
#include "xpath_compile_context.hpp"

namespace Arabica
{
namespace XPath
{
namespace impl
{

template<class string_type, class string_adaptor>
class StepExpression : public XPathExpression<string_type, string_adaptor>
{
public:
  StepExpression() { }
  StepExpression(const std::vector<XPathExpression<string_type, string_adaptor> *>& predicates) : predicates_(predicates) { }

  virtual ~StepExpression()
  { 
    for(typename std::vector<XPathExpression<string_type, string_adaptor>*>::iterator p = predicates_.begin(), e = predicates_.end(); p != e; ++p)
      delete *p;
  } // ~StepExpression

  virtual XPathValuePtr<string_type> evaluate(const DOM::Node<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const = 0;
  virtual XPathValuePtr<string_type> evaluate(NodeSet<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const = 0;

  bool has_predicates() const { return !predicates_.empty(); }

protected:
  NodeSet<string_type> applyPredicates(NodeSet<string_type>& nodes, const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    for(typename std::vector<XPathExpression<string_type, string_adaptor>*>::const_iterator p = predicates_.begin(), e = predicates_.end();
        (p != e) && (!nodes.empty()); ++p)
      nodes = applyPredicate(nodes, *p, parentContext);
    return nodes;
  } // applyPredicates

private:
  NodeSet<string_type> applyPredicate(NodeSet<string_type>& nodes, 
                                      XPathExpression<string_type, string_adaptor>* predicate, 
                                      const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    ExecutionContext<string_type, string_adaptor> executionContext(nodes.size(), parentContext);
    NodeSet<string_type> results(nodes.forward());
    unsigned int position = 1;
    for(typename NodeSet<string_type>::iterator i = nodes.begin(); i != nodes.end(); ++i, ++position)
    {
      executionContext.setPosition(position);
      XPathValuePtr<string_type> v = predicate->evaluate(*i, executionContext);

      if((v->type() == NUMBER) && (position != v->asNumber()))
        continue;
      if(v->asBool() == false)
        continue;

      results.push_back(*i);
    } // for ...
    return results;
  } // applyPredicate
  
  std::vector<XPathExpression<string_type, string_adaptor>*> predicates_;
}; // StepExpression

template<class string_type, class string_adaptor>
class TestStepExpression : public StepExpression<string_type, string_adaptor>
{
  typedef StepExpression<string_type, string_adaptor> baseT;
public:
  TestStepExpression(Axis axis, NodeTest<string_type>* test) :
      StepExpression<string_type, string_adaptor>(),
      axis_(axis),
      test_(test)
  {
  } // TestStepExpression

  TestStepExpression(Axis axis, NodeTest<string_type>* test, 
                     const std::vector<XPathExpression<string_type, string_adaptor>*>& predicates) :
      StepExpression<string_type, string_adaptor>(predicates),
      axis_(axis),
      test_(test)
  {
  } // TestStepExpression

  virtual ~TestStepExpression()
  {
    delete test_;
  } // StepExpression

  virtual XPathValuePtr<string_type> evaluate(const DOM::Node<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    NodeSet<string_type> nodes;
    enumerateOver(context, nodes, executionContext);
    return XPathValuePtr<string_type>(new NodeSetValue<string_type, string_adaptor>(nodes));
  } // evaluate

  virtual XPathValuePtr<string_type> evaluate(NodeSet<string_type>& context, const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    NodeSet<string_type> nodes;
    for(typename NodeSet<string_type>::iterator n = context.begin(); n != context.end(); ++n)
      enumerateOver(*n, nodes, executionContext);
    return XPathValuePtr<string_type>(new NodeSetValue<string_type, string_adaptor>(nodes));
  } // evaluate

private:
  void enumerateOver(const DOM::Node<string_type>& context, 
                     NodeSet<string_type>& results, 
                     const ExecutionContext<string_type, string_adaptor>& parentContext) const
  {
    AxisEnumerator<string_type, string_adaptor> enumerator(context, axis_);
    results.forward(enumerator.forward());
    NodeSet<string_type> intermediate(enumerator.forward());
    NodeSet<string_type>& d = (!baseT::has_predicates()) ? results : intermediate;
    while(*enumerator != 0)
    {
      // if test
      DOM::Node<string_type> node = *enumerator;
      if((*test_)(node))
        d.push_back(node);
      ++enumerator;
    } // while ...
    
    if(!baseT::has_predicates())
      return;

    intermediate = baseT::applyPredicates(intermediate, parentContext);

    results.insert(results.end(), intermediate.begin(), intermediate.end());
  } // enumerateOver

  Axis axis_;
  NodeTest<string_type>* test_;
}; // class TestStepExpression

template<class string_type, class string_adaptor>
class ExprStepExpression : public StepExpression<string_type, string_adaptor>
{
  typedef StepExpression<string_type, string_adaptor> baseT;
public:
  ExprStepExpression(XPathExpression<string_type, string_adaptor>* expr, 
                     const std::vector<XPathExpression<string_type, string_adaptor>*>& predicates) :
      StepExpression<string_type, string_adaptor>(predicates),
      expr_(expr)
  {
  } // ExprStepExpression

  virtual ~ExprStepExpression()
  {
    delete expr_;
{'fraction_non_alphanumeric': 0.11760236386661038, 'fraction_numerical': 0.0010130856901646263, 'mean_word_length': 4.593012275731822, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 143, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7025516', 'n_tokens_mistral': 3664, 'n_tokens_neox': 3519, 'n_words': 668}