#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"
#include "VirtualPropertyTermDocumentIterator.h"

#include <algorithm>
#include <limits>

using namespace std;
using namespace sf1r;

ORDocumentIterator::ORDocumentIterator()
    :pDocIteratorQueue_(NULL)
    ,hasNot_(false)
    ,currDocOfNOTIter_(MAX_DOC_ID)
    ,initNOTIterator_(false)
    ,pNOTDocIterator_(NULL)
{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
            else
            {
                ///If a DocumentIterator does not contain member, remove it from docIteratorList_
                *iter = NULL;
                delete pDocIterator;
            }
        }
        iter ++;
    }
}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

void ORDocumentIterator::add(VirtualPropertyTermDocumentIterator* pDocIterator)
{
    docIteratorList_.push_back(pDocIterator);
    std::sort( docIteratorList_.begin(), docIteratorList_.end() );
    docIteratorList_.erase( std::unique( docIteratorList_.begin(), docIteratorList_.end() ), docIteratorList_.end() );
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();

    if (! initNOTIterator_)
    {
        initNOTIterator_ = true;
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }

    bool ret = do_next();

    if (currDoc_ > currDocOfNOTIter_)
        currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);

    if (currDoc_ == currDocOfNOTIter_)
        return move_together_with_not();

    assert(currDoc_ < currDocOfNOTIter_);
    return ret;
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
            iter != docIteratorList_.end(); ++iter)
    {
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
            if((nFoundId != MAX_DOC_ID) && ((nFoundId == currentDoc) &&(currDocOfNOTIter_ == currentDoc)))
                return MAX_DOC_ID;
            currentDoc = nFoundId;
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
        {
            currDoc_ = MAX_DOC_ID;
            return MAX_DOC_ID;
        }
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        currDoc_ = MAX_DOC_ID;
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                currDoc_ = MAX_DOC_ID;
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    currDoc_ = MAX_DOC_ID;
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    }
    while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

void ORDocumentIterator:: setUB(bool useOriginalQuery, UpperBoundInProperties& ubmap)
{
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        (*it)->setUB(useOriginalQuery, ubmap);
    }

    unsigned short nItems = docI

    missRate_ = (missRate_ - nItems) / missRate_;
}

float ORDocumentIterator::getUB()
{
    float minUB = std::numeric_limits<float>::max();
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        if (!*it)
            continue;
        float ub = (*it)->getUB();
        if (ub < minUB )
            minUB = ub;
    }
    return minUB / (1 - missRate_);
}

count_t ORDocumentIterator::tf()
{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}


while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
            else
            {
                ///If a DocumentIterator does not contain member, remove it from docIteratorList_
                *iter = NULL;
                delete pDocIterator;
            }
        }
        iter ++;
    }

#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"
#include "VirtualPropertyTermDocumentIterator.h"

#include <algorithm>
#include <limits>

using namespace std;
using namespace sf1r;

ORDocumentIterator::ORDocumentIterator()
    :pDocIteratorQueue_(NULL)
    ,hasNot_(false)
    ,currDocOfNOTIter_(MAX_DOC_ID)
    ,initNOTIterator_(false)
    ,pNOTDocIterator_(NULL)
{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();

}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

void ORDocumentIterator::add(VirtualPropertyTermDocumentIterator* pDocIterator)
{
    docIteratorList_.push_back(pDocIterator);
    std::sort( docIteratorList_.begin(), docIteratorList_.end() );
    docIteratorList_.erase( std::unique( docIteratorList_.begin(), docIteratorList_.end() ), docIteratorList_.end() );
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();

    if (! initNOTIterator_)
    {
        initNOTIterator_ = true;
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }

    bool ret = do_next();

    if (currDoc_ > currDocOfNOTIter_)
        currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);

    if (currDoc_ == currDocOfNOTIter_)
        return move_together_with_not();

    assert(currDoc_ < currDocOfNOTIter_);
    return ret;
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
            iter != docIteratorList_.end(); ++iter)
    {
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
            if((nFoundId != MAX_DOC_ID) && ((nFoundId == currentDoc) &&(currDocOfNOTIter_ == currentDoc)))
                return MAX_DOC_ID;
            currentDoc = nFoundId;
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
        {
            currDoc_ = MAX_DOC_ID;
            return MAX_DOC_ID;
        }
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        currDoc_ = MAX_DOC_ID;
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                currDoc_ = MAX_DOC_ID;
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    currDoc_ = MAX_DOC_ID;
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    }
    while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

void ORDocumentIterator:: setUB(bool useOriginalQuery, UpperBoundInProperties& ubmap)
{
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        (*it)->setUB(useOriginalQuery, ubmap);
    }

    unsigned short nItems = docIteratorList_.size();
    missRate_ = (missRate_ - nItems) / missRate_;
}

float ORDocumentIterator::getUB()
{
    float minUB = std::numeric_limits<float>::max();
    std::vector<DocumentIterator*>::iterator it = docIteratorList_.begin();
    for (; it != docIteratorList_.end(); it++)
    {
        if (!*it)
            continue;
        float ub = (*it)->getUB();
        if (ub < minUB )
            minUB = ub;
    }
    return minUB / (1 - missRate_);
}

count_t ORDocumentIterator::tf()
{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}


#include "Calculator.h"
#include "SuperSensor.h"

#if defined (ARDUINO_ARCH_AVR)
#include <MemoryFree.h>
#endif

#if defined(__arm__)
extern "C" char* sbrk(int incr);

{
  char top = 't';
  return &top - reinterpret_cast<char*>(sbrk(0));
}

#endif
Calculator::Calculator( Scheduler* aS, Scheduler* aSensors) : Task(aS) {
  iS = aSensors;
  setTimeout(1000 * TASK_MILLISECOND);
}

bool Calculator::Callback() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcCallback: calculating");
  if ( getStatusRequest()->getStatus() >= 0) {  // only calculate if statusrequest ended successfully
    Serial.print("CalcCallback: Max distance="); Serial.println(distance);
  }
  return false;
}

extern int pins[];

bool Calculator::OnEnable() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcEnable: OnEnable");
  Serial.println("Activating sensors");

  StatusRequest* sr = getStatusRequest();
  iNS = sr->getCount();

  distance = 0;
  for (int i = 0; i < iNS; i++) {
    SuperSensor *s = new SuperSensor( iS, pins[i], this, sr);
    s->setId(i + 1);
    s->begin();
    s->restartDelayed();
  }

  return true;
}

void Calculator::OnDisable() {
  if ( timedOut() ) {
    getStatusRequest()->signalComplete(-1);  // signal error
    Serial.print(millis()); Serial.print(":\t");
    Serial.println("MeasureCallback: ***** Timeout *****");
  }
  iS->disableAll(false); // only disable tasks in the ts scheduler
#if defined (ARDUINO_ARCH_AVR) || defined(__arm__)
  Serial.print("Free mem = "); Serial.println(freeMemory()); Serial.println();
#endif
}

void Calculator::reportDistance(long aD) {
  if (distance < aD) distance = aD;
}


{
  iS = aSensors;
  setTimeout(1000 * TASK_MILLISECOND);
}

#include "Calculator.h"
#include "SuperSensor.h"

#if defined (ARDUINO_ARCH_AVR)
#include <MemoryFree.h>
#endif

#if defined(__arm__)
extern "C" char* sbrk(int incr);
static int freeMemory() {
  char top = 't';
  return &top - reinterpret_cast<char*>(sbrk(0));
}

#endif
Calculator::Calculator( Scheduler* aS, Scheduler* aSensors) : Task(aS)

bool Calculator::Callback() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcCallback: calculating");
  if ( getStatusRequest()->getStatus() >= 0) {  // only calculate if statusrequest ended successfully
    Serial.print("CalcCallback: Max distance="); Serial.println(distance);
  }
  return false;
}

extern int pins[];

bool Calculator::OnEnable() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcEnable: OnEnable");
  Serial.println("Activating sensors");

  StatusRequest* sr = getStatusRequest();
  iNS = sr->getCount();

  distance = 0;
  for (int i = 0; i < iNS; i++) {
    SuperSensor *s = new SuperSensor( iS, pins[i], this, sr);
    s->setId(i + 1);
    s->begin();
    s->restartDelayed();
  }

  return true;
}

void Calculator::OnDisable() {
  if ( timedOut() ) {
    getStatusRequest()->signalComplete(-1);  // signal error
    Serial.print(millis()); Serial.print(":\t");
    Serial.println("MeasureCallback: ***** Timeout *****");
  }
  iS->disableAll(false); // only disable tasks in the ts scheduler
#if defined (ARDUINO_ARCH_AVR) || defined(__arm__)
  Serial.print("Free mem = "); Serial.println(freeMemory()); Serial.println();
#endif
}

void Calculator::reportDistance(long aD) {
  if (distance < aD) distance = aD;
}


#include "Calculator.h"
#include "SuperSensor.h"

#if defined (ARDUINO_ARCH_AVR)
#include <MemoryFree.h>
#endif

#if defined(__arm__)
extern "C" char* sbrk(int incr);
static int freeMemory() {
  char top = 't';
  return &top - reinterpret_cast<char*>(sbrk(0));
}

#endif
Calculator::Calculator( Scheduler* aS, Scheduler* aSensors) : Task(aS) {
  iS = aSensors;
  setTimeout(1000 * TASK_MILLISECOND);
}

bool Calculator::Callback() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcCallback: c

  if ( getStatusRequest()->getStatus() >= 0) {  // only calculate if statusrequest ended successfully
    Serial.print("CalcCallback: Max distance="); Serial.println(distance);
  }
  return false;
}

extern int pins[];

bool Calculator::OnEnable() {
  Serial.print(millis()); Serial.print(":\t");
  Serial.println("CalcEnable: OnEnable");
  Serial.println("Activating sensors");

  StatusRequest* sr = getStatusRequest();
  iNS = sr->getCount();

  distance = 0;
  for (int i = 0; i < iNS; i++) {
    SuperSensor *s = new SuperSensor( iS, pins[i], this, sr);
    s->setId(i + 1);
    s->begin();
    s->restartDelayed();
  }

  return true;
}

void Calculator::OnDisable() {
  if ( timedOut() ) {
    getStatusRequest()->signalComplete(-1);  // signal error
    Serial.print(millis()); Serial.print(":\t");
    Serial.println("MeasureCallback: ***** Timeout *****");
  }
  iS->disableAll(false); // only disable tasks in the ts scheduler
#if defined (ARDUINO_ARCH_AVR) || defined(__arm__)
  Serial.print("Free mem = "); Serial.println(freeMemory()); Serial.println();
#endif
}

void Calculator::reportDistance(long aD) {
  if (distance < aD) distance = aD;
}


double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2)

{
        int m = nums1.size(), n = nums2.size();
        if (m > n) {
            swap(nums1, nums2);
            swap(m, n);
        }
        if (m == 0)
            return n % 2 == 0 ? static_cast<double>(nums2[n / 2 - 1] + nums2[n / 2]) / 2 : nums2[n / 2];
        int i = 0, j = m, half = (m + n + 1) / 2;
        while (i < j) {
            int k = i + (j - i) / 2, l = half - k;
            if (nums1[k] < nums2[l - 1])
                i = k + 1;
            else
                j = k;
        }
        int r1 = i, r2 = half - i;
        int res1 = max(r1 - 1 >= 0 ? nums1[r1 - 1] : INT_MIN, r2 - 1 >= 0 ? nums2[r2 - 1] : INT_MIN);
        if ((m + n) % 2)
            return res1;
        int res2 = min(r1 < m ? nums1[r1] : INT_MAX, r2 < n ? nums2[r2] : INT_MAX);
        return static_cast<double>(res1 + res2) / 2;
    }
};


class Solution {
public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
        int m = nums1.size(), n = nums2.size();
        if (m > n) {
            swap(nums1, nums2);
            swap(m, n);
        }
        if (m == 0)
            return n % 2 == 0 ? static_cast<double>(nums2[n / 2 - 1] + nums2[n / 2]) / 2 : nums2[n / 2];
        int i = 0, j = m, half = (m + n + 1) / 2;
        while (i < j) {
            int k = i + (j - i) / 2, l = half - k;
            if (nums1[k] < nums2[l - 1])
                i = k + 1;
            else
                j = k;
        }
        int r

        int res1 = max(r1 - 1 >= 0 ? nums1[r1 - 1] : INT_MIN, r2 - 1 >= 0 ? nums2[r2 - 1] : INT_MIN);
        if ((m + n) % 2)
            return res1;
        int res2 = min(r1 < m ? nums1[r1] : INT_MAX, r2 < n ? nums2[r2] : INT_MAX);
        return static_cast<double>(res1 + res2) / 2;
    }
};


while (i < j) {
            int k = i + (j - i) / 2, l = half - k;
            if (nums1[k] < nums2[l - 1])
                i = k + 1;
            else
                j = k;
        }

class Solution {
public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
        int m = nums1.size(), n = nums2.size();
        if (m > n) {
            swap(nums1, nums2);
            swap(m, n);
        }
        if (m == 0)
            return n % 2 == 0 ? static_cast<double>(nums2[n / 2 - 1] + nums2[n / 2]) / 2 : nums2[n / 2];
        int i = 0, j = m, half = (m + n + 1) / 2;

        int r1 = i, r2 = half - i;
        int res1 = max(r1 - 1 >= 0 ? nums1[r1 - 1] : INT_MIN, r2 - 1 >= 0 ? nums2[r2 - 1] : INT_MIN);
        if ((m + n) % 2)
            return res1;
        int res2 = min(r1 < m ? nums1[r1] : INT_MAX, r2 < n ? nums2[r2] : INT_MAX);
        return static_cast<double>(res1 + res2) / 2;
    }
};


std::tuple<Tensor, Tensor> AdaptiveMaxPool1dImpl::forward_with_indices(const Tensor& input)

#include <torch/nn/modules/pooling.h>

#include <torch/expanding_array.h>

namespace F = torch::nn::functional;

namespace torch {
namespace nn {

template <size_t D, typename Derived>
AvgPoolImpl<D, Derived>::AvgPoolImpl(const AvgPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::AvgPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor AvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad());
}

Tensor AvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

Tensor AvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

template class AvgPoolImpl<1, AvgPool1dImpl>;
template class AvgPoolImpl<2, AvgPool2dImpl>;
template class AvgPoolImpl<3, AvgPool3dImpl>;

template <size_t D, typename Derived>
MaxPoolImpl<D, Derived>::MaxPoolImpl(const MaxPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding()
         << ", dilation=" << options.dilation()
         << ", ceil_mode=" << options.ceil_mode() << ")";
}

Tensor MaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::max_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool1dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool1d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::max_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool2d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::max_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool3d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

template class MaxPoolImpl<1, MaxPool1dImpl>;
template class MaxPoolImpl<2, MaxPool2dImpl>;
template class MaxPoolImpl<3, MaxPool3dImpl>;

Tensor AdaptiveMaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool1d(input, options.output_size());
}

{
  return F::detail::adaptive_max_pool1d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool2d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool2d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool3d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool3d_with_indices(input, options.output_size());
}

template class AdaptiveMaxPoolImpl<1, ExpandingArray<1>, AdaptiveMaxPool1dImpl>;
template class AdaptiveMaxPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveMaxPool2dImpl>;
template class AdaptiveMaxPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveMaxPool3dImpl>;

Tensor AdaptiveAvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool1d(input, options.output_size());
}

Tensor AdaptiveAvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool2d(input, options.output_size());
}

Tensor AdaptiveAvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool3d(input, options.output_size());
}

template class AdaptiveAvgPoolImpl<1, ExpandingArray<1>, AdaptiveAvgPool1dImpl>;
template class AdaptiveAvgPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveAvgPool2dImpl>;
template class AdaptiveAvgPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveAvgPool3dImpl>;

template <size_t D, typename Derived>
MaxUnpoolImpl<D, Derived>::MaxUnpoolImpl(const MaxUnpoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxUnpool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor MaxUnpool1dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool1d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool2dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool2d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool3dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool3d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

template class MaxUnpoolImpl<1, MaxUnpool1dImpl>;
template class MaxUnpoolImpl<2, MaxUnpool2dImpl>;
template class MaxUnpoolImpl<3, MaxUnpool3dImpl>;

FractionalMaxPool2dImpl::FractionalMaxPool2dImpl(const FractionalMaxPool2dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool2dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool2d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool2d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool2d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool2dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool2d()";
}

FractionalMaxPool3dImpl::FractionalMaxPool3dImpl(const FractionalMaxPool3dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool3dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool3d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1 &&
          0 < output_ratio[2] && output_ratio[2] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool3d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool3d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool3dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool3d()";
}

template <size_t D, typename Derived>
LPPoolImpl<D, Derived>::LPPoolImpl(const LPPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::LPPool" << D << "d("
         << "norm_type=" << options.norm_type() << ", "
         << "kernel_size=" << options.kernel_size() << ", "
         << "stride=" << options.stride() << ", "
         << "ceil_mode=" << options.ceil_mode() << ")";
}

Tensor LPPool1dImpl::forward(const Tensor& input) {
  return F::detail::lp_pool1d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

template class LPPoolImpl<1, LPPool1dImpl>;

Tensor LPPool2dImpl::forward(const Tensor& input) {
  return F::detail::lp_pool2d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

template class LPPoolImpl<2, LPPool2dImpl>;

} // namespace nn
} // namespace torch


{
  return F::detail::lp_pool2d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

#include <torch/nn/modules/pooling.h>

#include <torch/expanding_array.h>

namespace F = torch::nn::functional;

namespace torch {
namespace nn {

template <size_t D, typename Derived>
AvgPoolImpl<D, Derived>::AvgPoolImpl(const AvgPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::AvgPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor AvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad());
}

Tensor AvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

Tensor AvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

template class AvgPoolImpl<1, AvgPool1dImpl>;
template class AvgPoolImpl<2, AvgPool2dImpl>;
template class AvgPoolImpl<3, AvgPool3dImpl>;

template <size_t D, typename Derived>
MaxPoolImpl<D, Derived>::MaxPoolImpl(const MaxPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding()
         << ", dilation=" << options.dilation()
         << ", ceil_mode=" << options.ceil_mode() << ")";
}

Tensor MaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::max_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool1dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool1d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::max_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool2d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::max_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool3d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

template class MaxPoolImpl<1, MaxPool1dImpl>;
template class MaxPoolImpl<2, MaxPool2dImpl>;
template class MaxPoolImpl<3, MaxPool3dImpl>;

Tensor AdaptiveMaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool1d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool1dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool1d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool2d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool2d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool3d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool3d_with_indices(input, options.output_size());
}

template class AdaptiveMaxPoolImpl<1, ExpandingArray<1>, AdaptiveMaxPool1dImpl>;
template class AdaptiveMaxPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveMaxPool2dImpl>;
template class AdaptiveMaxPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveMaxPool3dImpl>;

Tensor AdaptiveAvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool1d(input, options.output_size());
}

Tensor AdaptiveAvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool2d(input, options.output_size());
}

Tensor AdaptiveAvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool3d(input, options.output_size());
}

template class AdaptiveAvgPoolImpl<1, ExpandingArray<1>, AdaptiveAvgPool1dImpl>;
template class AdaptiveAvgPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveAvgPool2dImpl>;
template class AdaptiveAvgPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveAvgPool3dImpl>;

template <size_t D, typename Derived>
MaxUnpoolImpl<D, Derived>::MaxUnpoolImpl(const MaxUnpoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxUnpool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor MaxUnpool1dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool1d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool2dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool2d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool3dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool3d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

template class MaxUnpoolImpl<1, MaxUnpool1dImpl>;
template class MaxUnpoolImpl<2, MaxUnpool2dImpl>;
template class MaxUnpoolImpl<3, MaxUnpool3dImpl>;

FractionalMaxPool2dImpl::FractionalMaxPool2dImpl(const FractionalMaxPool2dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool2dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool2d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool2d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool2d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool2dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool2d()";
}

FractionalMaxPool3dImpl::FractionalMaxPool3dImpl(const FractionalMaxPool3dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool3dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool3d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1 &&
          0 < output_ratio[2] && output_ratio[2] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool3d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool3d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool3dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool3d()";
}

template <size_t D, typename Derived>
LPPoolImpl<D, Derived>::LPPoolImpl(const LPPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::LPPool" << D << "d("
         << "norm_type=" << options.norm_type() << ", "
         << "kernel_size=" << options.kernel_size() << ", "
         << "stride=" << options.stride() << ", "
         << "ceil_mode=" << options.ceil_mode() << ")";
}

Tensor LPPool1dImpl::forward(const Tensor& input) {
  return F::detail::lp_pool1d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

template class LPPoolImpl<1, LPPool1dImpl>;

Tensor LPPool2dImpl::forward(const Tensor& input)

template class LPPoolImpl<2, LPPool2dImpl>;

} // namespace nn
} // namespace torch


#include <torch/nn/modules/pooling.h>

#include <torch/expanding_array.h>

namespace F = torch::nn::functional;

namespace torch {
namespace nn {

template <size_t D, typename Derived>
AvgPoolImpl<D, Derived>::AvgPoolImpl(const AvgPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void AvgPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::AvgPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor AvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad());
}

Tensor AvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

Tensor AvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::avg_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.ceil_mode(),
    options.count_include_pad(),
    options.divisor_override());
}

template class AvgPoolImpl<1, AvgPool1dImpl>;
template class AvgPoolImpl<2, AvgPool2dImpl>;
template class AvgPoolImpl<3, AvgPool3dImpl>;

template <size_t D, typename Derived>
MaxPoolImpl<D, Derived>::MaxPoolImpl(const MaxPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxPool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding()
         << ", dilation=" << options.dilation()
         << ", ceil_mode=" << options.ceil_mode() << ")";
}

Tensor MaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::max_pool1d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool1dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool1d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::max_pool2d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool2d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

Tensor MaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::max_pool3d(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

std::tuple<Tensor, Tensor> MaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::max_pool3d_with_indices(
    input,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    options.dilation(),
    options.ceil_mode());
}

template class MaxPoolImpl<1, MaxPool1dImpl>;
template class MaxPoolImpl<2, MaxPool2dImpl>;
template class MaxPoolImpl<3, MaxPool3dImpl>;

Tensor AdaptiveMaxPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool1d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool1dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool1d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool2d(input, options.output_size());
}

std::tuple<Tensor, Tensor> AdaptiveMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool2d_with_indices(input, options.output_size());
}

Tensor AdaptiveMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_max_pool3d(input, options.outp

}

std::tuple<Tensor, Tensor> AdaptiveMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::adaptive_max_pool3d_with_indices(input, options.output_size());
}

template class AdaptiveMaxPoolImpl<1, ExpandingArray<1>, AdaptiveMaxPool1dImpl>;
template class AdaptiveMaxPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveMaxPool2dImpl>;
template class AdaptiveMaxPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveMaxPool3dImpl>;

Tensor AdaptiveAvgPool1dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool1d(input, options.output_size());
}

Tensor AdaptiveAvgPool2dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool2d(input, options.output_size());
}

Tensor AdaptiveAvgPool3dImpl::forward(const Tensor& input) {
  return F::detail::adaptive_avg_pool3d(input, options.output_size());
}

template class AdaptiveAvgPoolImpl<1, ExpandingArray<1>, AdaptiveAvgPool1dImpl>;
template class AdaptiveAvgPoolImpl<2, ExpandingArrayWithOptionalElem<2>, AdaptiveAvgPool2dImpl>;
template class AdaptiveAvgPoolImpl<3, ExpandingArrayWithOptionalElem<3>, AdaptiveAvgPool3dImpl>;

template <size_t D, typename Derived>
MaxUnpoolImpl<D, Derived>::MaxUnpoolImpl(const MaxUnpoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void MaxUnpoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::MaxUnpool" << D << "d"
         << "(kernel_size=" << options.kernel_size()
         << ", stride=" << options.stride()
         << ", padding=" << options.padding() << ")";
}

Tensor MaxUnpool1dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool1d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool2dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool2d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

Tensor MaxUnpool3dImpl::forward(const Tensor& input, const Tensor& indices,
    const c10::optional<std::vector<int64_t>>& output_size) {
  return F::detail::max_unpool3d(
    input,
    indices,
    options.kernel_size(),
    options.stride(),
    options.padding(),
    output_size);
}

template class MaxUnpoolImpl<1, MaxUnpool1dImpl>;
template class MaxUnpoolImpl<2, MaxUnpool2dImpl>;
template class MaxUnpoolImpl<3, MaxUnpool3dImpl>;

FractionalMaxPool2dImpl::FractionalMaxPool2dImpl(const FractionalMaxPool2dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool2dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool2d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool2dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool2d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool2dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool2d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool2dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool2d()";
}

FractionalMaxPool3dImpl::FractionalMaxPool3dImpl(const FractionalMaxPool3dOptions& options_) // NOLINT(modernize-pass-by-value)
    : options(options_) {
  reset();
}

void FractionalMaxPool3dImpl::reset() {
  _random_samples = register_buffer("_random_samples", options._random_samples());
  if (options.output_size() == c10::nullopt && options.output_ratio() == c10::nullopt) {
    TORCH_CHECK(
      false,
      "FractionalMaxPool3d requires specifying either ",
      "an output size, or a pooling ratio");
  }
  if (options.output_size() != c10::nullopt && options.output_ratio() != c10::nullopt) {
    TORCH_CHECK(false, "only one of output_size and output_ratio may be specified");
  }
  if (options.output_ratio() != c10::nullopt) {
    at::ArrayRef<double> output_ratio = at::ArrayRef<double>(options.output_ratio().value());
    if (!(0 < output_ratio[0] && output_ratio[0] < 1 &&
          0 < output_ratio[1] && output_ratio[1] < 1 &&
          0 < output_ratio[2] && output_ratio[2] < 1)) {
      TORCH_CHECK(false, "output_ratio must be between 0 and 1 (got ", output_ratio, ")");
    }
  }
}

Tensor FractionalMaxPool3dImpl::forward(const Tensor& input) {
  return F::detail::fractional_max_pool3d(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

std::tuple<Tensor, Tensor> FractionalMaxPool3dImpl::forward_with_indices(const Tensor& input) {
  return F::detail::fractional_max_pool3d_with_indices(
            input, options.kernel_size(), options.output_size(), options.output_ratio(),
            _random_samples);
}

void FractionalMaxPool3dImpl::pretty_print(std::ostream& stream) const {
  stream << "torch::nn::FractionalMaxPool3d()";
}

template <size_t D, typename Derived>
LPPoolImpl<D, Derived>::LPPoolImpl(const LPPoolOptions<D>& options_)
    : options(options_) {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::reset() {}

template <size_t D, typename Derived>
void LPPoolImpl<D, Derived>::pretty_print(std::ostream& stream) const {
  stream << std::boolalpha
         << "torch::nn::LPPool" << D << "d("
         << "norm_type=" << options.norm_type() << ", "
         << "kernel_size=" << options.kernel_size() << ", "
         << "stride=" << options.stride() << ", "
         << "ceil_mode=" << options.ceil_mode() << ")";
}

Tensor LPPool1dImpl::forward(const Tensor& input) {
  return F::detail::lp_pool1d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

template class LPPoolImpl<1, LPPool1dImpl>;

Tensor LPPool2dImpl::forward(const Tensor& input) {
  return F::detail::lp_pool2d(
    input,
    options.norm_type(),
    options.kernel_size(),
    options.stride(),
    options.ceil_mode());
}

template class LPPoolImpl<2, LPPool2dImpl>;

} // namespace nn
} // namespace torch


CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode)

/*
*******************************************************************************
*******************************************************************************
*   file name:  charstr.cpp
*   encoding:   UTF-8
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2010may19
*   created by: Markus W. Scherer
*/

#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "uinvchar.h"
#include "ustr_imp.h"

U_NAMESPACE_BEGIN

CharString::CharString(CharString&& src) U_NOEXCEPT
        : buffer(std::move(src.buffer)), len(src.len) {
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
}

CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
    buffer = std::move(src.buffer);
    len = src.len;
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
    return *this;
}

char *CharString::cloneData(UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return nullptr; }
    char *p = static_cast<char *>(uprv_malloc(len + 1));
    if (p == nullptr) {
        errorCode = U_MEMORY_ALLOCATION_ERROR;
        return nullptr;
    }
    uprv_memcpy(p, buffer.getAlias(), len + 1);
    return p;
}

int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return len; }
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
        return len;
    }
    const char *src = buffer.getAlias();
    if (0 < len && len <= capacity && src != dest) {
        uprv_memcpy(dest, src, len);
    }
    return u_terminateChars(dest, capacity, len, &errorCode);
}

{
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
        len=s.len;
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
    }
    return *this;
}

int32_t CharString::lastIndexOf(char c) const {
    for(int32_t i=len; i>0;) {
        if(buffer[--i]==c) {
            return i;
        }
    }
    return -1;
}

bool CharString::contains(StringPiece s) const {
    if (s.empty()) { return false; }
    const char *p = buffer.getAlias();
    int32_t lastStart = len - s.length();
    for (int32_t i = 0; i <= lastStart; ++i) {
        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
            return true;
        }
    }
    return false;
}

CharString &CharString::truncate(int32_t newLength) {
    if(newLength<0) {
        newLength=0;
    }
    if(newLength<len) {
        buffer[len=newLength]=0;
    }
    return *this;
}

CharString &CharString::append(char c, UErrorCode &errorCode) {
    if(ensureCapacity(len+2, 0, errorCode)) {
        buffer[len++]=c;
        buffer[len]=0;
    }
    return *this;
}

CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(sLength<-1 || (s==NULL && sLength!=0)) {
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
        return *this;
    }
    if(sLength<0) {
        sLength= static_cast<int32_t>(uprv_strlen(s));
    }
    if(sLength>0) {
        if(s==(buffer.getAlias()+len)) {
            // The caller wrote into the getAppendBuffer().
            if(sLength>=(buffer.getCapacity()-len)) {
                // The caller wrote too much.
                errorCode=U_INTERNAL_PROGRAM_ERROR;
            } else {
                buffer[len+=sLength]=0;
            }
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
                  sLength>=(buffer.getCapacity()-len)
        ) {
            // (Part of) this string is appended to itself which requires reallocation,
            // so we have to make a copy of the substring and append that.
            return append(CharString(s, sLength, errorCode), errorCode);
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
            buffer[len+=sLength]=0;
        }
    }
    return *this;
}

char *CharString::getAppendBuffer(int32_t minCapacity,
                                  int32_t desiredCapacityHint,
                                  int32_t &resultCapacity,
                                  UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        resultCapacity=0;
        return NULL;
    }
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
    if(appendCapacity>=minCapacity) {
        resultCapacity=appendCapacity;
        return buffer.getAlias()+len;
    }
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
        resultCapacity=buffer.getCapacity()-len-1;
        return buffer.getAlias()+len;
    }
    resultCapacity=0;
    return NULL;
}

CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
}

CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
        errorCode = U_INVARIANT_CONVERSION_ERROR;
        return *this;
    }
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
        len += ucharsLen;
        buffer[len] = 0;
    }
    return *this;
}

UBool CharString::ensureCapacity(int32_t capacity,
                                 int32_t desiredCapacityHint,
                                 UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return FALSE;
    }
    if(capacity>buffer.getCapacity()) {
        if(desiredCapacityHint==0) {
            desiredCapacityHint=capacity+buffer.getCapacity();
        }
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
            buffer.resize(capacity, len+1)==NULL
        ) {
            errorCode=U_MEMORY_ALLOCATION_ERROR;
            return FALSE;
        }
    }
    return TRUE;
}

CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(s.length()==0) {
        return *this;
    }
    char c;
    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    append(s, errorCode);
    return *this;
}

CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
    char c;
    if(U_SUCCESS(errorCode) && len>0 &&
            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    return *this;
}

char CharString::getDirSepChar() const {
    char dirSepChar = U_FILE_SEP_CHAR;
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    // We may need to return a different directory separator when building for Cygwin or MSYS2.
    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
        dirSepChar = U_FILE_ALT_SEP_CHAR;
#endif
    return dirSepChar;
}

U_NAMESPACE_END


{
    char c;
    if(U_SUCCESS(errorCode) && len>0 &&
            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    return *this;
}

/*
*******************************************************************************
*******************************************************************************
*   file name:  charstr.cpp
*   encoding:   UTF-8
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2010may19
*   created by: Markus W. Scherer
*/

#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "uinvchar.h"
#include "ustr_imp.h"

U_NAMESPACE_BEGIN

CharString::CharString(CharString&& src) U_NOEXCEPT
        : buffer(std::move(src.buffer)), len(src.len) {
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
}

CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
    buffer = std::move(src.buffer);
    len = src.len;
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
    return *this;
}

char *CharString::cloneData(UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return nullptr; }
    char *p = static_cast<char *>(uprv_malloc(len + 1));
    if (p == nullptr) {
        errorCode = U_MEMORY_ALLOCATION_ERROR;
        return nullptr;
    }
    uprv_memcpy(p, buffer.getAlias(), len + 1);
    return p;
}

int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return len; }
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
        return len;
    }
    const char *src = buffer.getAlias();
    if (0 < len && len <= capacity && src != dest) {
        uprv_memcpy(dest, src, len);
    }
    return u_terminateChars(dest, capacity, len, &errorCode);
}

CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
        len=s.len;
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
    }
    return *this;
}

int32_t CharString::lastIndexOf(char c) const {
    for(int32_t i=len; i>0;) {
        if(buffer[--i]==c) {
            return i;
        }
    }
    return -1;
}

bool CharString::contains(StringPiece s) const {
    if (s.empty()) { return false; }
    const char *p = buffer.getAlias();
    int32_t lastStart = len - s.length();
    for (int32_t i = 0; i <= lastStart; ++i) {
        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
            return true;
        }
    }
    return false;
}

CharString &CharString::truncate(int32_t newLength) {
    if(newLength<0) {
        newLength=0;
    }
    if(newLength<len) {
        buffer[len=newLength]=0;
    }
    return *this;
}

CharString &CharString::append(char c, UErrorCode &errorCode) {
    if(ensureCapacity(len+2, 0, errorCode)) {
        buffer[len++]=c;
        buffer[len]=0;
    }
    return *this;
}

CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(sLength<-1 || (s==NULL && sLength!=0)) {
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
        return *this;
    }
    if(sLength<0) {
        sLength= static_cast<int32_t>(uprv_strlen(s));
    }
    if(sLength>0) {
        if(s==(buffer.getAlias()+len)) {
            // The caller wrote into the getAppendBuffer().
            if(sLength>=(buffer.getCapacity()-len)) {
                // The caller wrote too much.
                errorCode=U_INTERNAL_PROGRAM_ERROR;
            } else {
                buffer[len+=sLength]=0;
            }
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
                  sLength>=(buffer.getCapacity()-len)
        ) {
            // (Part of) this string is appended to itself which requires reallocation,
            // so we have to make a copy of the substring and append that.
            return append(CharString(s, sLength, errorCode), errorCode);
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
            buffer[len+=sLength]=0;
        }
    }
    return *this;
}

char *CharString::getAppendBuffer(int32_t minCapacity,
                                  int32_t desiredCapacityHint,
                                  int32_t &resultCapacity,
                                  UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        resultCapacity=0;
        return NULL;
    }
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
    if(appendCapacity>=minCapacity) {
        resultCapacity=appendCapacity;
        return buffer.getAlias()+len;
    }
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
        resultCapacity=buffer.getCapacity()-len-1;
        return buffer.getAlias()+len;
    }
    resultCapacity=0;
    return NULL;
}

CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
}

CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
        errorCode = U_INVARIANT_CONVERSION_ERROR;
        return *this;
    }
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
        len += ucharsLen;
        buffer[len] = 0;
    }
    return *this;
}

UBool CharString::ensureCapacity(int32_t capacity,
                                 int32_t desiredCapacityHint,
                                 UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return FALSE;
    }
    if(capacity>buffer.getCapacity()) {
        if(desiredCapacityHint==0) {
            desiredCapacityHint=capacity+buffer.getCapacity();
        }
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
            buffer.resize(capacity, len+1)==NULL
        ) {
            errorCode=U_MEMORY_ALLOCATION_ERROR;
            return FALSE;
        }
    }
    return TRUE;
}

CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(s.length()==0) {
        return *this;
    }
    char c;
    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    append(s, errorCode);
    return *this;
}

CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode)

char CharString::getDirSepChar() const {
    char dirSepChar = U_FILE_SEP_CHAR;
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    // We may need to return a different directory separator when building for Cygwin or MSYS2.
    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
        dirSepChar = U_FILE_ALT_SEP_CHAR;
#endif
    return dirSepChar;
}

U_NAMESPACE_END


/*
*******************************************************************************
*******************************************************************************
*   file name:  charstr.cpp
*   encoding:   UTF-8
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2010may19
*   created by: Markus W. Scherer
*/

#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "uinvchar.h"
#include "ustr_imp.h"

U_NAMESPACE_BEGIN

CharString::CharString(CharString&& src) U_NOEXCEPT
        : buffer(std::move(src.buffer)), len(src.len) {
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
}

CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
    buffer = std::move(src.buffer);
    len = src.len;
    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
    return *this;
}

char *CharString::cloneData(UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return nullptr; }
    char *p = static_cast<char *>(uprv_malloc(len + 1));
    if (p == nullptr) {
        errorCode = U_MEMORY_ALLOCATION_ERROR;
        return nullptr;
    }
    uprv_memcpy(p, buffer.getAlias(), len + 1);
    return p;
}

int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
    if (U_FAILURE(errorCode)) { return len; }
    if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
        return len;
    }
    const char *src = buffer.getAlias();
    if (0 < len && len <= capacity && src != dest) {
        uprv_memcpy(dest, src, len);
    }
    return u_terminateChars(dest, capacity, len, &errorCode);
}

CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
        len=s.len;
        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
    }
    return

}

int32_t CharString::lastIndexOf(char c) const {
    for(int32_t i=len; i>0;) {
        if(buffer[--i]==c) {
            return i;
        }
    }
    return -1;
}

bool CharString::contains(StringPiece s) const {
    if (s.empty()) { return false; }
    const char *p = buffer.getAlias();
    int32_t lastStart = len - s.length();
    for (int32_t i = 0; i <= lastStart; ++i) {
        if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
            return true;
        }
    }
    return false;
}

CharString &CharString::truncate(int32_t newLength) {
    if(newLength<0) {
        newLength=0;
    }
    if(newLength<len) {
        buffer[len=newLength]=0;
    }
    return *this;
}

CharString &CharString::append(char c, UErrorCode &errorCode) {
    if(ensureCapacity(len+2, 0, errorCode)) {
        buffer[len++]=c;
        buffer[len]=0;
    }
    return *this;
}

CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(sLength<-1 || (s==NULL && sLength!=0)) {
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
        return *this;
    }
    if(sLength<0) {
        sLength= static_cast<int32_t>(uprv_strlen(s));
    }
    if(sLength>0) {
        if(s==(buffer.getAlias()+len)) {
            // The caller wrote into the getAppendBuffer().
            if(sLength>=(buffer.getCapacity()-len)) {
                // The caller wrote too much.
                errorCode=U_INTERNAL_PROGRAM_ERROR;
            } else {
                buffer[len+=sLength]=0;
            }
        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
                  sLength>=(buffer.getCapacity()-len)
        ) {
            // (Part of) this string is appended to itself which requires reallocation,
            // so we have to make a copy of the substring and append that.
            return append(CharString(s, sLength, errorCode), errorCode);
        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
            uprv_memcpy(buffer.getAlias()+len, s, sLength);
            buffer[len+=sLength]=0;
        }
    }
    return *this;
}

char *CharString::getAppendBuffer(int32_t minCapacity,
                                  int32_t desiredCapacityHint,
                                  int32_t &resultCapacity,
                                  UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        resultCapacity=0;
        return NULL;
    }
    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
    if(appendCapacity>=minCapacity) {
        resultCapacity=appendCapacity;
        return buffer.getAlias()+len;
    }
    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
        resultCapacity=buffer.getCapacity()-len-1;
        return buffer.getAlias()+len;
    }
    resultCapacity=0;
    return NULL;
}

CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
    return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
}

CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if (!uprv_isInvariantUString(uchars, ucharsLen)) {
        errorCode = U_INVARIANT_CONVERSION_ERROR;
        return *this;
    }
    if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
        u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
        len += ucharsLen;
        buffer[len] = 0;
    }
    return *this;
}

UBool CharString::ensureCapacity(int32_t capacity,
                                 int32_t desiredCapacityHint,
                                 UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return FALSE;
    }
    if(capacity>buffer.getCapacity()) {
        if(desiredCapacityHint==0) {
            desiredCapacityHint=capacity+buffer.getCapacity();
        }
        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
            buffer.resize(capacity, len+1)==NULL
        ) {
            errorCode=U_MEMORY_ALLOCATION_ERROR;
            return FALSE;
        }
    }
    return TRUE;
}

CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return *this;
    }
    if(s.length()==0) {
        return *this;
    }
    char c;
    if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    append(s, errorCode);
    return *this;
}

CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
    char c;
    if(U_SUCCESS(errorCode) && len>0 &&
            (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
        append(getDirSepChar(), errorCode);
    }
    return *this;
}

char CharString::getDirSepChar() const {
    char dirSepChar = U_FILE_SEP_CHAR;
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
    // We may need to return a different directory separator when building for Cygwin or MSYS2.
    if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
        dirSepChar = U_FILE_ALT_SEP_CHAR;
#endif
    return dirSepChar;
}

U_NAMESPACE_END