← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/skip-items into lp:zorba

 

Nicolae Brinza has proposed merging lp:~zorba-coders/zorba/skip-items into lp:zorba.

Commit message:
Implemented the Skip-items facility

Requested reviews:
  Nicolae Brinza (nbrinza)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Implemented the Skip-items facility
-- 
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'src/functions/func_sequences_impl.cpp'
--- src/functions/func_sequences_impl.cpp	2013-05-14 05:21:11 +0000
+++ src/functions/func_sequences_impl.cpp	2013-07-15 10:38:33 +0000
@@ -43,127 +43,6 @@
 
 
 /*******************************************************************************
-
-********************************************************************************/
-bool rewriteSubsequenceCollection(
-    static_context* aSctx,
-    const QueryLoc& aLoc,
-    std::vector<PlanIter_t>& aArgs,
-    bool aIsIntSubsequence)
-{
-  ZorbaCollectionIterator* collIter = 
-  dynamic_cast<ZorbaCollectionIterator*>(aArgs[0].getp());
-  assert(collIter);
-
-  std::vector<PlanIter_t>& lCollectionArgs = collIter->getChildren();
-
-  SingletonIterator* lPosIter = dynamic_cast<SingletonIterator*>(aArgs[1].getp());
-  if (lPosIter == NULL)
-  {
-    return false;
-  }
-
-  xs_long pos;
-  const store::Item_t& lPosItem = lPosIter->getValue();
-
-  try
-  {
-    if (aIsIntSubsequence)
-    {
-      pos = lPosItem->getLongValue();
-    }
-    else
-    {
-      xs_double dpos = lPosItem->getDoubleValue().round();
-      xs_integer ipos(dpos.getNumber());
-      pos = to_xs_long(ipos);
-    }
-  }
-  catch (std::exception const&)
-  {
-    return false;
-  }
-
-  if (pos <= 1)
-  {
-    // if the start position is less than 1 we can't push this down into
-    // the collection skip parameter because the result won't be equivalent.
-    return false;
-  }
-
-  // prepare helper
-  store::Item_t lItemOne;
-  GENV_ITEMFACTORY->createInteger(lItemOne, Integer(1));
-
-  int lNumCollArgs = lCollectionArgs.size();
-  if (lNumCollArgs == 1)
-  {
-    // argument is of type collection(qname)
-    // simply move the (pos-1) of subsequence into the skip of 
-    // collection function
-    // subsequence(collection(qname), 10, 20) 
-    //   -> subsequence(collection(qname, 10-1), 1, 20)
-    PlanIter_t& lNewCollSkipIter = aArgs[1];
-    PlanIter_t lOneIter = new SingletonIterator(aSctx, aLoc, lItemOne);
-
-    lCollectionArgs.push_back(
-      new NumArithIterator<zorba::SubtractOperation>(aSctx,
-                                                     collIter->getLocation(),
-                                                     lNewCollSkipIter,
-                                                     lOneIter)
-                              );
-  }
-  else if (lNumCollArgs <= 3 && lNumCollArgs != 0)
-  {
-    // argument is of type collection(qname,skip) or 
-    // collection(qname,start_uri,skip)
-    int lSkipPosition = 1;
-    if (lNumCollArgs == 3) 
-    {
-      // collection function with start reference -> skip is the 3rd param
-      lSkipPosition = 2;
-    }
-      
-    // add position-1 of subsequence to collection skip
-    // subsequence(collection(qname, 10), 10, 20) 
-    //   -> subsequence(collection(qname, 10+10-1), 10, 20)
-    PlanIter_t& lOldCollSkipIter = lCollectionArgs[lSkipPosition];
-    PlanIter_t lOneIter = new SingletonIterator (aSctx, aLoc, lItemOne);
-    PlanIter_t& lSubseqPosIter = aArgs[1];
-
-    PlanIter_t lCollSkipAdditionIter = 
-    new NumArithIterator<zorba::SubtractOperation>(aSctx,
-                                                   collIter->getLocation(),
-                                                   lSubseqPosIter,
-                                                   lOneIter);
-    lCollectionArgs[lSkipPosition] = 
-    new NumArithIterator<zorba::AddOperation>(aSctx,
-                                              collIter->getLocation(), 
-                                              lOldCollSkipIter,
-                                              lCollSkipAdditionIter);
-  }
-  else
-  {
-    // no collection function with 0 or >3 params
-    assert(false);
-  }
-
-  aArgs[0] = new ZorbaCollectionIterator(aSctx,
-                                         collIter->getLocation(),
-                                         lCollectionArgs,
-                                         collIter->isDynamic());
-
-  // after pushing the position param down we need to rewrite the actual 
-  // position to 1:
-  // subsequence(collection(qname, 10+10-1), 10, 20) 
-  //   -> subsequence(collection(qname, 10+10-1), 1, 20)
-  aArgs[1] = new SingletonIterator(aSctx, aLoc, lItemOne);
-
-  return true;
-}
-
-
-/*******************************************************************************
 ********************************************************************************/
 xqtref_t fn_unordered::getReturnType(const fo_expr* caller) const
 {
@@ -573,8 +452,7 @@
     const QueryLoc& aLoc,
     std::vector<PlanIter_t>& aArgs,
     expr& aAnn) const
-{
-  const std::type_info& lFirstArgType = typeid(*aArgs[0]);
+{  
   fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);
   const expr* inputExpr = subseqExpr.get_arg(0);
   const expr* posExpr = subseqExpr.get_arg(1);
@@ -619,23 +497,8 @@
         return aArgs[0];
     }
   }
-  else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
-  {
-    // push down position param into collection skip if possible
-    if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, false /*no int*/))
-    {
-      // we have rewritten the subsequence to start at the beginning.
-      // if there is no length param we can remove the entire
-      // subsequence function
-      // subsequence(collection(qname, 10), 1) -> collection(qname, 10)
-      if (aArgs.size() == 2)
-      {
-        return aArgs[0];
-      }
-    }
-  }
 
- done:
+done:
   return new FnSubsequenceIterator(aSctx, aLoc, aArgs);
 }
 
@@ -736,23 +599,8 @@
       return aArgs[0];
     }
   }
-  else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
-  {
-    // push down position param into collection skip if possible
-    if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, true /*flag int*/))
-    {
-      // we have rewritten the subsequence to start from the beginning.
-      // if there is no length param we can remove the entire
-      // subsequence function
-      // subsequence(collection(qname, 10), 1) -> collection(qname, 10)
-      if (aArgs.size() == 2)
-      {
-        return aArgs[0];
-      }
-    }
-  }
 
- done:
+done:
   return new SubsequenceIntIterator(aSctx, aLoc, aArgs);
 }
 

=== modified file 'src/runtime/base/plan_iterator.cpp'
--- src/runtime/base/plan_iterator.cpp	2013-05-28 18:20:54 +0000
+++ src/runtime/base/plan_iterator.cpp	2013-07-15 10:38:33 +0000
@@ -31,6 +31,10 @@
 
 #include "diagnostics/util_macros.h"
 
+#ifndef NDEBUG
+#include "system/properties.h"
+#endif
+
 namespace zorba
 {
 
@@ -180,6 +184,18 @@
 }
 
 
+bool PlanIterator::skip(int64_t count, PlanState& planState) const
+{
+  bool have_more_items = true;
+  store::Item_t item;
+
+  while (count-- > 0 && (have_more_items = consumeNext(item, this, planState)))
+    ;
+
+  return have_more_items;
+}
+
+
 #ifndef NDEBUG
 bool PlanIterator::consumeNext(
     store::Item_t& result,
@@ -196,7 +212,12 @@
 
   if (planState.theCompilerCB->theConfig.print_item_flow)
   {
-    std::cout << "next (" << iter << " = " << typeid (*iter).name()
+    if (Properties::instance()->stableIteratorIds())
+      std::cout << "next (" << iter->getId();
+    else
+      std::cout << "next (" << iter;
+
+    std::cout << " = " << typeid (*iter).name()
               << ") -> "
               << "status: " << status << " -> "
               << ((status && result != NULL) ? result->show().c_str() : "null")

=== modified file 'src/runtime/base/plan_iterator.h'
--- src/runtime/base/plan_iterator.h	2013-05-28 18:20:54 +0000
+++ src/runtime/base/plan_iterator.h	2013-07-15 10:38:33 +0000
@@ -401,6 +401,19 @@
   virtual bool count(store::Item_t& result, PlanState& planState) const;
 
   /**
+   * Skip a number of items from the Plan's sequence. Classes can overwrite
+   * this functions to optimize the skipping by jumping directly to the
+   * desired position in the sequence.
+   *
+   * Returns true if the entire sequence has been consumed, false otherwise.
+   *
+   * @param count the number of items to be skipped
+   * @param planState the state plan
+   *
+   */
+  virtual bool skip(int64_t count, PlanState &planState) const;
+
+  /**
    * Produce the next item and return it to the caller. Implicitly, the first
    * call of 'producNext' initializes the iterator and allocates resources
    * (main memory, file descriptors, etc.).

=== modified file 'src/runtime/collections/collections_impl.cpp'
--- src/runtime/collections/collections_impl.cpp	2013-05-02 18:34:27 +0000
+++ src/runtime/collections/collections_impl.cpp	2013-07-15 10:38:33 +0000
@@ -277,17 +277,13 @@
 }
 
 
-bool ZorbaCollectionIterator::nextImpl(
-    store::Item_t& result,
-    PlanState& planState) const
+void ZorbaCollectionIterator::initCollection(PlanState& planState, int64_t skipCount) const
 {
   store::Item_t name;
+  xs_integer lSkip;
   store::Collection_t collection;
-  xs_integer lSkip;
-  zstring lStart;
 
-  ZorbaCollectionIteratorState* state;
-  DEFAULT_STACK_INIT(ZorbaCollectionIteratorState, state, planState);
+  ZorbaCollectionIteratorState* state = StateTraitsImpl<ZorbaCollectionIteratorState>::getState(planState, theStateOffset);
 
   consumeNext(name, theChildren[0].getp(), planState);
 
@@ -299,12 +295,13 @@
   }
   else
   {
+    zstring lStart;
     bool lRefPassed = theChildren.size() >= 3;
-    
+
     // read positional skip parameter
     store::Item_t lSkipItem;
     consumeNext(lSkipItem, theChildren[(lRefPassed ? 2 : 1)].getp(), planState);
-    lSkip = lSkipItem->getIntegerValue(); 
+    lSkip = lSkipItem->getIntegerValue();
 
     // negative skip is not allowed
     if (lSkip.sign() < 0)
@@ -314,16 +311,16 @@
 
     if (!lRefPassed)
     {
-      state->theIterator = collection->getIterator(lSkip);
+      state->theIterator = collection->getIterator(lSkip + skipCount);
     }
     else
     {
       store::Item_t lRefItem;
       consumeNext(lRefItem, theChildren[1].getp(), planState);
-      lStart = lRefItem->getString(); 
+      lStart = lRefItem->getString();
       try
       {
-        state->theIterator = collection->getIterator(lSkip, lStart);
+        state->theIterator = collection->getIterator(lSkip + skipCount, lStart);
       }
       catch (ZorbaException& e)
       {
@@ -346,6 +343,29 @@
   }
 
   state->theIteratorOpened = true;
+}
+
+
+bool ZorbaCollectionIterator::nextImpl(
+    store::Item_t& result,
+    PlanState& planState) const
+{
+  store::Item_t name;
+  xs_integer lSkip;
+  store::Collection_t collection;
+
+  ZorbaCollectionIteratorState* state;
+  DEFAULT_STACK_INIT(ZorbaCollectionIteratorState, state, planState);
+
+  if (state->theIterator.getp() != NULL && state->theIteratorOpened == false)
+  {
+    ZORBA_ASSERT (false && "nextImpl() called past iterator end");
+    return false;
+  }
+  else if (state->theIteratorOpened == false)
+  {
+    initCollection(planState, 0);
+  }
 
   while (state->theIterator->next(result))
     STACK_PUSH(true, state);
@@ -358,6 +378,36 @@
 }
 
 
+bool ZorbaCollectionIterator::skip(int64_t count, PlanState& planState) const
+{  
+  ZorbaCollectionIteratorState* state = StateTraitsImpl<ZorbaCollectionIteratorState>::getState(planState, theStateOffset);
+
+  if (state->theIterator.getp() != NULL && state->theIteratorOpened == false)
+  {
+    ZORBA_ASSERT (false && "nextImpl() called past iterator end");
+    return false;
+  }
+  else if (state->theIteratorOpened == false)
+  {
+    initCollection(planState, count);
+  }
+
+  store::Item_t result;
+  bool have_more_items = true;
+  while (count-- > 0 && (have_more_items = state->theIterator->next(result)))
+    ;
+
+  if ( ! have_more_items)
+  {
+    // close as early as possible
+    state->theIterator->close();
+    state->theIteratorOpened = false;
+  }
+
+  return have_more_items;
+}
+
+
 bool ZorbaCollectionIterator::count(store::Item_t& result, PlanState& planState) const
 {
   if (!isCountOptimizable())

=== modified file 'src/runtime/collections/pregenerated/collections.h'
--- src/runtime/collections/pregenerated/collections.h	2013-03-24 20:40:03 +0000
+++ src/runtime/collections/pregenerated/collections.h	2013-07-15 10:38:33 +0000
@@ -291,6 +291,8 @@
 public:
   bool isCountOptimizable() const;
   bool count(store::Item_t& result, PlanState& planState) const;
+  bool skip(int64_t count, PlanState& planState) const;
+  void initCollection(PlanState& planState, int64_t skipCount) const;
   void accept(PlanIterVisitor& v) const;
 
   bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;

=== modified file 'src/runtime/sequences/sequences_impl.cpp'
--- src/runtime/sequences/sequences_impl.cpp	2013-06-18 18:55:33 +0000
+++ src/runtime/sequences/sequences_impl.cpp	2013-07-15 10:38:33 +0000
@@ -533,11 +533,8 @@
     goto done;
 
   // Consume and skip all input items that are before the startPos
-  for (; startPos > 1; --startPos)
-  {
-    if (!CONSUME(result, 0))
-      goto done;
-  }
+  if (!theChildren[0]->skip(startPos-1, planState))
+    goto done;
 
   if (theChildren.size() < 3 || lengthDouble.isPosInf())
   {
@@ -619,11 +616,8 @@
     goto done;
 
   // Consume and skip all input items that are before the startPos
-  for (; startPos > 0; --startPos)
-  {
-    if (!CONSUME(result, 0))
-      goto done;
-  }
+  if (!theChildren[0]->skip(startPos, planState))
+    goto done;
 
   if (theChildren.size() < 3)
   {
@@ -694,11 +688,8 @@
   --startPos;
 
   // Consume and skip all input items that are before the startPos
-  for (; startPos > 0; --startPos)
-  {
-    if (!CONSUME(result, 0))
-      goto done;
-  }
+  if (!theChildren[0]->skip(startPos, planState))
+    goto done;
 
   if (CONSUME(result, 0))
   {

=== modified file 'src/runtime/spec/collections/collections.xml'
--- src/runtime/spec/collections/collections.xml	2013-04-02 22:54:20 +0000
+++ src/runtime/spec/collections/collections.xml	2013-07-15 10:38:33 +0000
@@ -313,6 +313,16 @@
        <zorba:param name="result" type="store::Item_t&amp;"/>
        <zorba:param name="planState" type="PlanState&amp;"/>
     </zorba:method>
+    
+    <zorba:method name="skip" const="true" return="bool">
+      <zorba:param name="count" type="int64_t"/>
+      <zorba:param name="planState" type="PlanState&amp;"/>
+    </zorba:method>
+    
+    <zorba:method name="initCollection" const="true" return="void">
+      <zorba:param name="planState" type="PlanState&amp;"/>
+      <zorba:param name="skipCount" type="int64_t"/>
+    </zorba:method>
 
     <zorba:state generateInit="false" generateReset="false" generateDestructor="false">
       <zorba:member type="store::Iterator_t" name="theIterator"/>


Follow ups