<commit_before>/*=============================================================================

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=============================================================================*/

#include "ctkCmdLineModuleManager.h"

#include "ctkCmdLineModuleBackend.h"
#include "ctkCmdLineModuleFrontend.h"
#include "ctkCmdLineModuleCache_p.h"
#include "ctkCmdLineModuleFuture.h"
#include "ctkCmdLineModuleXmlValidator.h"
#include "ctkCmdLineModuleReference.h"
#include "ctkCmdLineModuleReference_p.h"

#include <ctkException.h>

#include <QFileInfo>
#include <QDir>
#include <QStringList>
#include <QBuffer>
#include <QUrl>
#include <QHash>
#include <QList>
#include <QMutex>

#include <QFuture>

//----------------------------------------------------------------------------
struct ctkCmdLineModuleManagerPrivate
{
  ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir)
    : ValidationMode(mode)
  {
    QFileInfo fileInfo(cacheDir);
    if (!fileInfo.exists())
    {
      if (!QDir().mkpath(cacheDir))
      {
        qWarning() << "Command line module cache disabled. Directory" << cacheDir << "could not be created.";
        return;
      }
    }

    if (fileInfo.isWritable())
    {
      ModuleCache.reset(new ctkCmdLineModuleCache(cacheDir));
    }
    else
    {
      qWarning() << "Command line module cache disabled. Directory" << cacheDir << "is not writable.";
    }
  }

  void checkBackends_unlocked(const QUrl& location)
  {
    if (!this->SchemeToBackend.contains(location.scheme()))
    {
      throw ctkInvalidArgumentException(QString("No suitable backend registered for module at ") + location.toString());
    }
  }

  QMutex Mutex;
  QHash<QString, ctkCmdLineModuleBackend*> SchemeToBackend;
  QHash<QUrl, ctkCmdLineModuleReference> LocationToRef;
  QScopedPointer<ctkCmdLineModuleCache> ModuleCache;

  const ctkCmdLineModuleManager::ValidationMode ValidationMode;
};

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir)
  : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir))
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::~ctkCmdLineModuleManager()
{
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend)
{
  QMutexLocker lock(&d->Mutex);

  QList<QString> supportedSchemes = backend->schemes();

  // Check if there is already a backend registerd for any of the
  // supported schemes. We only supported one backend per scheme.
  foreach (QString scheme, supportedSchemes)
  {
    if (d->SchemeToBackend.contains(scheme))
    {
      throw ctkInvalidArgumentException(QString("A backend for scheme %1 is already registered.").arg(scheme));
    }
  }

  // All good
  foreach (QString scheme, supportedSchemes)
  {
    d->SchemeToBackend[scheme] = backend;
  }
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference
ctkCmdLineModuleManager::registerModule(const QUrl &location)
{
  QByteArray xml;
  ctkCmdLineModuleBackend* backend = NULL;
  {
    QMutexLocker lock(&d->Mutex);

    d->checkBackends_unlocked(location);

    // If the module is already registered, just return the reference
    if (d->LocationToRef.contains(location))
    {
      return d->LocationToRef[location];
    }

    backend = d->SchemeToBackend[location.scheme()];
  }

  bool fromCache = false;
  qint64 newTimeStamp = 0;
  if (d->ModuleCache)
  {
    newTimeStamp = backend->timeStamp(location);
    if (d->ModuleCache->timeStamp(location) < newTimeStamp)
    {
      // newly fetch the XML description
      try
      {
        xml = backend->rawXmlDescription(location);
      }
      catch (...)
      {
        // cache the failed attempt
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
        throw;
      }
    }
    else
    {
      // use the cached XML description
      xml = d->ModuleCache->rawXmlDescription(location);
      fromCache = true;
    }
  }
  else
  {
    xml = backend->rawXmlDescription(location);
  }

  if (xml.isEmpty())
  {
    if (!fromCache && d->ModuleCache)
    {
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
    }
    throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString());
  }

  ctkCmdLineModuleReference ref;
  ref.d->Location = location;
  ref.d->RawXmlDescription = xml;
  ref.d->Backend = backend;

  if (d->ValidationMode != SKIP_VALIDATION)
  {
    // validate the outputted xml description
    QBuffer input(&xml);
    input.open(QIODevice::ReadOnly);

    ctkCmdLineModuleXmlValidator validator(&input);
    if (!validator.validateInput())
    {
      if (d->ModuleCache)
      {
        // validation failed, cache an empty description
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
      }

      if (d->ValidationMode == STRICT_VALIDATION)
      {
        throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2")
                                          .arg(location.toString()).arg(validator.errorString()));
      }
      else
      {
        ref.d->XmlValidationErrorString = validator.errorString();
      }
    }
    else
    {
      if (d->ModuleCache && newTimeStamp > 0)
      {
        // successfully validated the xml, cache it
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }
    }
  }
  else
  {
    if (!fromCache && d->ModuleCache)
    {
      // cache it
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
    }
  }

  {
    QMutexLocker lock(&d->Mutex);
    // Check that we don't have a race condition
    if (d->LocationToRef.contains(location))
    {
      // Another thread registered a module with the same location
      return d->LocationToRef[location];
    }
    d->LocationToRef[location] = ref;
  }

  emit moduleRegistered(ref);
  return ref;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
{
  if (!ref) return;

  {
    QMutexLocker lock(&d->Mutex);
    if (!d->LocationToRef.contains(ref.location()))
    {
      return;
    }
    d->LocationToRef.remove(ref.location());
    if (d->ModuleCache)
    {
      d->ModuleCache->removeCacheEntry(ref.location());
    }
  }
  emit moduleUnregistered(ref);
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef[location];
}

//----------------------------------------------------------------------------
QList<ctkCmdLineModuleReference> ctkCmdLineModuleManager::moduleReferences() const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef.values();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend)
{
  QMutexLocker lock(&d->Mutex);
  d->checkBackends_unlocked(frontend->location());

  ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend);
  frontend->setFuture(future);
  emit frontend->started();
  return future;
}
<commit_msg>Always cache the XML output of a module.<commit_after>/*=============================================================================

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=============================================================================*/

#include "ctkCmdLineModuleManager.h"

#include "ctkCmdLineModuleBackend.h"
#include "ctkCmdLineModuleFrontend.h"
#include "ctkCmdLineModuleCache_p.h"
#include "ctkCmdLineModuleFuture.h"
#include "ctkCmdLineModuleXmlValidator.h"
#include "ctkCmdLineModuleReference.h"
#include "ctkCmdLineModuleReference_p.h"

#include <ctkException.h>

#include <QFileInfo>
#include <QDir>
#include <QStringList>
#include <QBuffer>
#include <QUrl>
#include <QHash>
#include <QList>
#include <QMutex>

#include <QFuture>

//----------------------------------------------------------------------------
struct ctkCmdLineModuleManagerPrivate
{
  ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir)
    : ValidationMode(mode)
  {
    QFileInfo fileInfo(cacheDir);
    if (!fileInfo.exists())
    {
      if (!QDir().mkpath(cacheDir))
      {
        qWarning() << "Command line module cache disabled. Directory" << cacheDir << "could not be created.";
        return;
      }
    }

    if (fileInfo.isWritable())
    {
      ModuleCache.reset(new ctkCmdLineModuleCache(cacheDir));
    }
    else
    {
      qWarning() << "Command line module cache disabled. Directory" << cacheDir << "is not writable.";
    }
  }

  void checkBackends_unlocked(const QUrl& location)
  {
    if (!this->SchemeToBackend.contains(location.scheme()))
    {
      throw ctkInvalidArgumentException(QString("No suitable backend registered for module at ") + location.toString());
    }
  }

  QMutex Mutex;
  QHash<QString, ctkCmdLineModuleBackend*> SchemeToBackend;
  QHash<QUrl, ctkCmdLineModuleReference> LocationToRef;
  QScopedPointer<ctkCmdLineModuleCache> ModuleCache;

  const ctkCmdLineModuleManager::ValidationMode ValidationMode;
};

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir)
  : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir))
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::~ctkCmdLineModuleManager()
{
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend)
{
  QMutexLocker lock(&d->Mutex);

  QList<QString> supportedSchemes = backend->schemes();

  // Check if there is already a backend registerd for any of the
  // supported schemes. We only supported one backend per scheme.
  foreach (QString scheme, supportedSchemes)
  {
    if (d->SchemeToBackend.contains(scheme))
    {
      throw ctkInvalidArgumentException(QString("A backend for scheme %1 is already registered.").arg(scheme));
    }
  }

  // All good
  foreach (QString scheme, supportedSchemes)
  {
    d->SchemeToBackend[scheme] = backend;
  }
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference
ctkCmdLineModuleManager::registerModule(const QUrl &location)
{
  QByteArray xml;
  ctkCmdLineModuleBackend* backend = NULL;
  {
    QMutexLocker lock(&d->Mutex);

    d->checkBackends_unlocked(location);

    // If the module is already registered, just return the reference
    if (d->LocationToRef.contains(location))
    {
      return d->LocationToRef[location];
    }

    backend = d->SchemeToBackend[location.scheme()];
  }

  bool fromCache = false;
  qint64 newTimeStamp = 0;
  if (d->ModuleCache)
  {
    newTimeStamp = backend->timeStamp(location);
    if (d->ModuleCache->timeStamp(location) < newTimeStamp)
    {
      // newly fetch the XML description
      try
      {
        xml = backend->rawXmlDescription(location);
      }
      catch (...)
      {
        // cache the failed attempt
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
        throw;
      }
    }
    else
    {
      // use the cached XML description
      xml = d->ModuleCache->rawXmlDescription(location);
      fromCache = true;
    }
  }
  else
  {
    xml = backend->rawXmlDescription(location);
  }

  if (xml.isEmpty())
  {
    if (!fromCache && d->ModuleCache)
    {
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
    }
    throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString());
  }

  ctkCmdLineModuleReference ref;
  ref.d->Location = location;
  ref.d->RawXmlDescription = xml;
  ref.d->Backend = backend;

  if (d->ValidationMode != SKIP_VALIDATION)
  {
    // validate the outputted xml description
    QBuffer input(&xml);
    input.open(QIODevice::ReadOnly);

    ctkCmdLineModuleXmlValidator validator(&input);
    if (!validator.validateInput())
    {
      if (d->ModuleCache)
      {
        // validation failed, cache the description anyway
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }

      if (d->ValidationMode == STRICT_VALIDATION)
      {
        throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2")
                                          .arg(location.toString()).arg(validator.errorString()));
      }
      else
      {
        ref.d->XmlValidationErrorString = validator.errorString();
      }
    }
    else
    {
      if (d->ModuleCache && newTimeStamp > 0)
      {
        // successfully validated the xml, cache it
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }
    }
  }
  else
  {
    if (!fromCache && d->ModuleCache)
    {
      // cache it
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
    }
  }

  {
    QMutexLocker lock(&d->Mutex);
    // Check that we don't have a race condition
    if (d->LocationToRef.contains(location))
    {
      // Another thread registered a module with the same location
      return d->LocationToRef[location];
    }
    d->LocationToRef[location] = ref;
  }

  emit moduleRegistered(ref);
  return ref;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
{
  if (!ref) return;

  {
    QMutexLocker lock(&d->Mutex);
    if (!d->LocationToRef.contains(ref.location()))
    {
      return;
    }
    d->LocationToRef.remove(ref.location());
    if (d->ModuleCache)
    {
      d->ModuleCache->removeCacheEntry(ref.location());
    }
  }
  emit moduleUnregistered(ref);
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef[location];
}

//----------------------------------------------------------------------------
QList<ctkCmdLineModuleReference> ctkCmdLineModuleManager::moduleReferences() const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef.values();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend)
{
  QMutexLocker lock(&d->Mutex);
  d->checkBackends_unlocked(frontend->location());

  ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend);
  frontend->setFuture(future);
  emit frontend->started();
  return future;
}
<|endoftext|>


<commit_before>// -------
// License
// -------
//
// It is released under the MIT license.
//
//     Copyright (c) 2013 Hiroyuki Tanaka
//
//     Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
//     The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include <cstdlib>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <bitset>
#include <algorithm>

#include "./_editdistance.h"

using namespace std;

template<typename T, typename TVALUE>
unsigned int edit_distance_bpv(T &cmap, int64_t const *vec, size_t const &vecsize, unsigned int const &tmax, unsigned int const &tlen) {
    int D = tmax * 64 + tlen;
    TVALUE D0, HP, HN, VP, VN;
    uint64_t top = (1LL << (tlen - 1));  // 末尾のvectorに適用
    uint64_t lmb = (1LL << 63);

    for(size_t i = 0; i <= tmax; ++i) {
        VP[i] = 0;
        VN[i] = 0;
    }
    for(size_t i = 0; i < tmax; ++i) VP[i] = ~0;
    for(size_t i = 0; i < tlen; ++i) VP[tmax] |= (1LL << i);
    for(size_t i = 0; i < vecsize; ++i) {
        TVALUE &PM = cmap[vec[i]];
        for(int r = 0; r <= tmax; ++r) {
            uint64_t X = PM[r];
            if(r > 0 && (HN[r - 1] & lmb)) X |= 1LL;
            D0[r] = (((X & VP[r]) + VP[r]) ^ VP[r]) | X | VN[r];
            HP[r] = VN[r] | ~(D0[r] | VP[r]);
            HN[r] = D0[r] & VP[r];
            X = (HP[r] << 1LL);
            if(r == 0 || HP[r - 1] & lmb) X |= 1LL;
            VP[r] = (HN[r] << 1LL) | ~(D0[r] | X);
            if(r > 0 && (HN[r - 1] & lmb)) VP[r] |= 1LL;
            VN[r] = D0[r] & X;
        }
        if(HP[tmax] & top) ++D;
        else if(HN[tmax] & top) --D;
    }
    return D;
}

/// c.f. http://handasse.blogspot.com/2009/04/c_29.html
template<typename T>
unsigned int edit_distance_dp(T const *str1, size_t const size1, T const *str2, size_t const size2) {
    // vectorより固定長配列の方が速いが、文字列が長い時の保険でのみ呼ばれるのでサイズを決め打ちできない
    vector< vector<uint32_t> > d(size1 + 1, vector<uint32_t>(size2 + 1));
    for (int i = 0; i < size1 + 1; i++) d[i][0] = i;
    for (int i = 0; i < size2 + 1; i++) d[0][i] = i;
    for (int i = 1; i < size1 + 1; i++) {
        for (int j = 1; j < size2 + 1; j++) {
            d[i][j] = min(min(d[i-1][j], d[i][j-1]) + 1, d[i-1][j-1] + (str1[i-1] == str2[j-1] ? 0 : 1));
        }
    }
    return d[size1][size2];
}

template <size_t N>
struct varr {
    uint64_t arr_[N];
    uint64_t & operator[](size_t const &i) {
        return arr_[i];
    }
};

template<size_t N>
unsigned int edit_distance_map_(int64_t const *a, size_t const asize, int64_t const *b, size_t const bsize) {
    typedef map<int64_t, varr<N> > cmap_v;
    cmap_v cmap;
    unsigned int tmax = (asize - 1) >> 6;
    unsigned int tlen = asize - tmax * 64;
    for(size_t i = 0; i < tmax; ++i) {
        for(size_t j = 0; j < 64; ++j) cmap[a[i * 64 + j]][i] |= (1LL << j);
    }
    for(size_t i = 0; i < tlen; ++i) cmap[a[tmax * 64 + i]][tmax] |= (1LL << i);
    return edit_distance_bpv<cmap_v, typename cmap_v::mapped_type>(cmap, b, bsize, tmax, tlen);
}

unsigned int edit_distance(const int64_t *a, const unsigned int asize, const int64_t *b, const unsigned int bsize) {
    if(asize == 0) return bsize;
    else if(bsize == 0) return asize;
    // 要素数の大きいほうがa
    int64_t const *ap, *bp;
    unsigned int const *asizep, *bsizep;
    if(asize < bsize) ap = b, bp = a, asizep = &bsize, bsizep = &asize;
    else ap = a, bp = b, asizep = &asize, bsizep = &bsize;
    // 必要な配列サイズを調べる
    size_t vsize = ((*asizep - 1) >> 6) + 1;  // 64までは1, 128までは2, ...
    // bit-parallelでできそうな限界を超えたら要素数の小さい方をaとする。
    if(vsize > 10) {
        int64_t const *_ = ap;
        unsigned int const *__ = asizep;
        ap = bp, bp = _, asizep = bsizep, bsizep = __;
        vsize = ((*asizep - 1) >> 6) + 1;
    }

    if(vsize == 1) return edit_distance_map_<1>(ap, *asizep, bp, *bsizep);
    else if(vsize == 2) return edit_distance_map_<2>(ap, *asizep, bp, *bsizep);
    else if(vsize == 3) return edit_distance_map_<3>(ap, *asizep, bp, *bsizep);
    else if(vsize == 4) return edit_distance_map_<4>(ap, *asizep, bp, *bsizep);
    else if(vsize == 5) return edit_distance_map_<5>(ap, *asizep, bp, *bsizep);
    else if(vsize == 6) return edit_distance_map_<6>(ap, *asizep, bp, *bsizep);
    else if(vsize == 7) return edit_distance_map_<7>(ap, *asizep, bp, *bsizep);
    else if(vsize == 8) return edit_distance_map_<8>(ap, *asizep, bp, *bsizep);
    else if(vsize == 9) return edit_distance_map_<9>(ap, *asizep, bp, *bsizep);
    else if(vsize == 10) return edit_distance_map_<10>(ap, *asizep, bp, *bsizep);
    return edit_distance_dp<int64_t>(ap, *asizep, bp, *bsizep);  // dynamic programmingに任せる
}
<commit_msg>Optimize the dynamic programming method<commit_after>// -------
// License
// -------
//
// It is released under the MIT license.
//
//     Copyright (c) 2013 Hiroyuki Tanaka
//
//     Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
//     The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include <cstdlib>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <bitset>
#include <algorithm>

#include "./_editdistance.h"

using namespace std;

template<typename T, typename TVALUE>
unsigned int edit_distance_bpv(T &cmap, int64_t const *vec, size_t const &vecsize, unsigned int const &tmax, unsigned int const &tlen) {
    int D = tmax * 64 + tlen;
    TVALUE D0, HP, HN, VP, VN;
    uint64_t top = (1LL << (tlen - 1));  // 末尾のvectorに適用
    uint64_t lmb = (1LL << 63);

    for(size_t i = 0; i <= tmax; ++i) {
        VP[i] = 0;
        VN[i] = 0;
    }
    for(size_t i = 0; i < tmax; ++i) VP[i] = ~0;
    for(size_t i = 0; i < tlen; ++i) VP[tmax] |= (1LL << i);
    for(size_t i = 0; i < vecsize; ++i) {
        TVALUE &PM = cmap[vec[i]];
        for(int r = 0; r <= tmax; ++r) {
            uint64_t X = PM[r];
            if(r > 0 && (HN[r - 1] & lmb)) X |= 1LL;
            D0[r] = (((X & VP[r]) + VP[r]) ^ VP[r]) | X | VN[r];
            HP[r] = VN[r] | ~(D0[r] | VP[r]);
            HN[r] = D0[r] & VP[r];
            X = (HP[r] << 1LL);
            if(r == 0 || HP[r - 1] & lmb) X |= 1LL;
            VP[r] = (HN[r] << 1LL) | ~(D0[r] | X);
            if(r > 0 && (HN[r - 1] & lmb)) VP[r] |= 1LL;
            VN[r] = D0[r] & X;
        }
        if(HP[tmax] & top) ++D;
        else if(HN[tmax] & top) --D;
    }
    return D;
}

/// c.f. http://handasse.blogspot.com/2009/04/c_29.html
template<typename T>
unsigned int edit_distance_dp(T const *str1, size_t const size1, T const *str2, size_t const size2) {
    // vectorより固定長配列の方が速いが、文字列が長い時の保険でのみ呼ばれるのでサイズを決め打ちできない
    vector< vector<uint32_t> > d(2, vector<uint32_t>(size2 + 1));
    d[0][0] = 0;
    d[1][0] = 1;
    for (int i = 0; i < size2 + 1; i++) d[0][i] = i;
    for (int i = 1; i < size1 + 1; i++) {
        for (int j = 1; j < size2 + 1; j++) {
            d[i&1][j] = min(min(d[(i-1)&1][j], d[i&1][j-1]) + 1, d[(i-1)&1][j-1] + (str1[i-1] == str2[j-1] ? 0 : 1));
        }
    }
    return d[size1&1][size2];
}

template <size_t N>
struct varr {
    uint64_t arr_[N];
    uint64_t & operator[](size_t const &i) {
        return arr_[i];
    }
};

template<size_t N>
unsigned int edit_distance_map_(int64_t const *a, size_t const asize, int64_t const *b, size_t const bsize) {
    typedef map<int64_t, varr<N> > cmap_v;
    cmap_v cmap;
    unsigned int tmax = (asize - 1) >> 6;
    unsigned int tlen = asize - tmax * 64;
    for(size_t i = 0; i < tmax; ++i) {
        for(size_t j = 0; j < 64; ++j) cmap[a[i * 64 + j]][i] |= (1LL << j);
    }
    for(size_t i = 0; i < tlen; ++i) cmap[a[tmax * 64 + i]][tmax] |= (1LL << i);
    return edit_distance_bpv<cmap_v, typename cmap_v::mapped_type>(cmap, b, bsize, tmax, tlen);
}

unsigned int edit_distance(const int64_t *a, const unsigned int asize, const int64_t *b, const unsigned int bsize) {
    if(asize == 0) return bsize;
    else if(bsize == 0) return asize;
    // 要素数の大きいほうがa
    int64_t const *ap, *bp;
    unsigned int const *asizep, *bsizep;
    if(asize < bsize) ap = b, bp = a, asizep = &bsize, bsizep = &asize;
    else ap = a, bp = b, asizep = &asize, bsizep = &bsize;
    // 必要な配列サイズを調べる
    size_t vsize = ((*asizep - 1) >> 6) + 1;  // 64までは1, 128までは2, ...
    // bit-parallelでできそうな限界を超えたら要素数の小さい方をaとする。
    if(vsize > 10) {
        int64_t const *_ = ap;
        unsigned int const *__ = asizep;
        ap = bp, bp = _, asizep = bsizep, bsizep = __;
        vsize = ((*asizep - 1) >> 6) + 1;
    }

    if(vsize == 1) return edit_distance_map_<1>(ap, *asizep, bp, *bsizep);
    else if(vsize == 2) return edit_distance_map_<2>(ap, *asizep, bp, *bsizep);
    else if(vsize == 3) return edit_distance_map_<3>(ap, *asizep, bp, *bsizep);
    else if(vsize == 4) return edit_distance_map_<4>(ap, *asizep, bp, *bsizep);
    else if(vsize == 5) return edit_distance_map_<5>(ap, *asizep, bp, *bsizep);
    else if(vsize == 6) return edit_distance_map_<6>(ap, *asizep, bp, *bsizep);
    else if(vsize == 7) return edit_distance_map_<7>(ap, *asizep, bp, *bsizep);
    else if(vsize == 8) return edit_distance_map_<8>(ap, *asizep, bp, *bsizep);
    else if(vsize == 9) return edit_distance_map_<9>(ap, *asizep, bp, *bsizep);
    else if(vsize == 10) return edit_distance_map_<10>(ap, *asizep, bp, *bsizep);
    return edit_distance_dp<int64_t>(ap, *asizep, bp, *bsizep);  // dynamic programmingに任せる
}
<|endoftext|>


<commit_before>#include "routing/geometry.hpp"

#include "routing/city_roads.hpp"
#include "routing/maxspeeds.hpp"
#include "routing/routing_exceptions.hpp"
#include "routing/routing_options.hpp"

#include "indexer/altitude_loader.hpp"
#include "indexer/classificator.hpp"
#include "indexer/data_source.hpp"
#include "indexer/ftypes_matcher.hpp"

#include "geometry/mercator.hpp"

#include "base/assert.hpp"
#include "base/string_utils.hpp"

#include <algorithm>
#include <string>

using namespace routing;
using namespace std;

namespace
{
// @TODO(bykoianko) Consider setting cache size based on available memory.
// Maximum road geometry cache size in items.
size_t constexpr kRoadsCacheSize = 5000;

double CalcFerryDurationHours(string const & durationHours, double roadLenKm)
{
  // Look for more info: https://confluence.mail.ru/display/MAPSME/Ferries
  // Shortly: the coefs were received from statistic about ferries with durations in OSM.
  double constexpr kIntercept = 0.2490726747447476;
  double constexpr kSlope = 0.02078913;

  if (durationHours.empty())
    return kIntercept + kSlope * roadLenKm;

  double durationH = 0.0;
  CHECK(strings::to_double(durationHours.c_str(), durationH), (durationHours));

  // See: https://confluence.mail.ru/download/attachments/249123157/image2019-8-22_16-15-53.png
  // Shortly: we drop some points: (x: lengthKm, y: durationH), that are upper or lower these two lines.
  double constexpr kUpperBoundIntercept = 4.0;
  double constexpr kUpperBoundSlope = 0.037;
  if (kUpperBoundIntercept + kUpperBoundSlope * roadLenKm - durationH < 0)
    return kIntercept + kSlope * roadLenKm;

  double constexpr kLowerBoundIntercept = -2.0;
  double constexpr kLowerBoundSlope = 0.015;
  if (kLowerBoundIntercept + kLowerBoundSlope * roadLenKm - durationH > 0)
    return kIntercept + kSlope * roadLenKm;

  return durationH;
}

// GeometryLoaderImpl ------------------------------------------------------------------------------
class GeometryLoaderImpl final : public GeometryLoader
{
public:
  GeometryLoaderImpl(DataSource const & dataSource, MwmSet::MwmHandle const & handle,
                     shared_ptr<VehicleModelInterface> vehicleModel,
                     AttrLoader attrLoader, bool loadAltitudes);

  // GeometryLoader overrides:
  void Load(uint32_t featureId, RoadGeometry & road) override;

private:
  shared_ptr<VehicleModelInterface> m_vehicleModel;
  AttrLoader m_attrLoader;
  FeaturesLoaderGuard m_guard;
  string const m_country;
  feature::AltitudeLoader m_altitudeLoader;
  bool const m_loadAltitudes;
};

GeometryLoaderImpl::GeometryLoaderImpl(DataSource const & dataSource,
                                       MwmSet::MwmHandle const & handle,
                                       shared_ptr<VehicleModelInterface> vehicleModel,
                                       AttrLoader attrLoader, bool loadAltitudes)
  : m_vehicleModel(move(vehicleModel))
  , m_attrLoader(move(attrLoader))
  , m_guard(dataSource, handle.GetId())
  , m_country(handle.GetInfo()->GetCountryName())
  , m_altitudeLoader(dataSource, handle.GetId())
  , m_loadAltitudes(loadAltitudes)
{
  CHECK(handle.IsAlive(), ());
  CHECK(m_vehicleModel, ());
  CHECK(m_attrLoader.m_cityRoads, ());
  CHECK(m_attrLoader.m_maxspeeds, ());
}

void GeometryLoaderImpl::Load(uint32_t featureId, RoadGeometry & road)
{
  auto feature = m_guard.GetFeatureByIndex(featureId);
  if (!feature)
    MYTHROW(RoutingException, ("Feature", featureId, "not found in ", m_country));

  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);

  feature::TAltitudes const * altitudes = nullptr;
  if (m_loadAltitudes)
    altitudes = &(m_altitudeLoader.GetAltitudes(featureId, feature->GetPointsCount()));

  road.Load(*m_vehicleModel, *feature, altitudes, m_attrLoader.m_cityRoads->IsCityRoad(featureId),
            m_attrLoader.m_maxspeeds->GetMaxspeed(featureId));
  m_altitudeLoader.ClearCache();
}

// FileGeometryLoader ------------------------------------------------------------------------------
class FileGeometryLoader final : public GeometryLoader
{
public:
  FileGeometryLoader(string const & fileName, shared_ptr<VehicleModelInterface> vehicleModel);

  // GeometryLoader overrides:
  void Load(uint32_t featureId, RoadGeometry & road) override;

private:
  FeaturesVectorTest m_featuresVector;
  CityRoads m_cityRoads;
  Maxspeeds m_maxspeeds;
  shared_ptr<VehicleModelInterface> m_vehicleModel;
};

FileGeometryLoader::FileGeometryLoader(string const & fileName,
                                       shared_ptr<VehicleModelInterface> vehicleModel)
  : m_featuresVector(FilesContainerR(make_unique<FileReader>(fileName)))
  , m_vehicleModel(vehicleModel)
{
  auto const cont = FilesContainerR(make_unique<FileReader>(fileName));

  try
  {
    if (cont.IsExist(CITY_ROADS_FILE_TAG))
      LoadCityRoads(fileName, cont.GetReader(CITY_ROADS_FILE_TAG), m_cityRoads);

    if (cont.IsExist(MAXSPEEDS_FILE_TAG))
      LoadMaxspeeds(cont.GetReader(MAXSPEEDS_FILE_TAG), m_maxspeeds);
  }
  catch (Reader::OpenException const & e)
  {
    LOG(LERROR, ("File", cont.GetFileName(), "Error while reading", CITY_ROADS_FILE_TAG, "or",
                 MAXSPEEDS_FILE_TAG, "section.", e.Msg()));
  }

  CHECK(m_vehicleModel, ());
}

void FileGeometryLoader::Load(uint32_t featureId, RoadGeometry & road)
{
  auto feature = m_featuresVector.GetVector().GetByIndex(featureId);
  CHECK(feature, ());
  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);
  // Note. If FileGeometryLoader is used for generation cross mwm section for bicycle or
  // pedestrian routing |altitudes| should be used here.
  road.Load(*m_vehicleModel, *feature, nullptr /* altitudes */, m_cityRoads.IsCityRoad(featureId),
            m_maxspeeds.GetMaxspeed(featureId));
}
}  // namespace

namespace routing
{
// RoadGeometry ------------------------------------------------------------------------------------
RoadGeometry::RoadGeometry(bool oneWay, double weightSpeedKMpH, double etaSpeedKMpH,
                           Points const & points)
  : m_forwardSpeed{weightSpeedKMpH, etaSpeedKMpH}
  , m_backwardSpeed(m_forwardSpeed)
  , m_isOneWay(oneWay)
  , m_valid(true)
{
  ASSERT_GREATER(weightSpeedKMpH, 0.0, ());
  ASSERT_GREATER(etaSpeedKMpH, 0.0, ());

  m_junctions.reserve(points.size());
  for (auto const & point : points)
    m_junctions.emplace_back(point, feature::kDefaultAltitudeMeters);
}

void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType & feature,
                        feature::TAltitudes const * altitudes, bool inCity, Maxspeed const & maxspeed)
{
  CHECK(altitudes == nullptr || altitudes->size() == feature.GetPointsCount(), ());

  m_valid = vehicleModel.IsRoad(feature);
  m_isOneWay = vehicleModel.IsOneWay(feature);
  m_forwardSpeed = vehicleModel.GetSpeed(feature, {true /* forward */, inCity, maxspeed});
  m_backwardSpeed = vehicleModel.GetSpeed(feature, {false /* forward */, inCity, maxspeed});
  m_highwayType = vehicleModel.GetHighwayType(feature);
  m_isPassThroughAllowed = vehicleModel.IsPassThroughAllowed(feature);

  feature::TypesHolder types(feature);
  auto const & optionsClassfier = RoutingOptionsClassifier::Instance();
  for (uint32_t type : types)
  {
    if (auto const it = optionsClassfier.Get(type))
      m_routingOptions.Add(*it);
  }

  m_junctions.clear();
  m_junctions.reserve(feature.GetPointsCount());
  for (size_t i = 0; i < feature.GetPointsCount(); ++i)
  {
    m_junctions.emplace_back(feature.GetPoint(i),
                             altitudes ? (*altitudes)[i] : feature::kDefaultAltitudeMeters);
  }

  if (m_routingOptions.Has(RoutingOptions::Road::Ferry))
  {
    auto const durationHours = feature.GetMetadata().Get(feature::Metadata::FMD_DURATION);
    auto const roadLenKm = GetRoadLengthM() / 1000.0;
    double durationH = CalcFerryDurationHours(durationHours, roadLenKm);

    CHECK(!base::AlmostEqualAbs(durationH, 0.0, 1e-5), (durationH));
    m_forwardSpeed = m_backwardSpeed =
        SpeedKMpH(std::min(vehicleModel.GetMaxWeightSpeed(), roadLenKm / durationH));
  }

  if (m_valid && (!m_forwardSpeed.IsValid() || !m_backwardSpeed.IsValid()))
  {
    auto const & id = feature.GetID();
    CHECK(!m_junctions.empty(), ("mwm:", id.GetMwmName(), ", featureId:", id.m_index));
    auto const begin = MercatorBounds::ToLatLon(m_junctions.front().GetPoint());
    auto const end = MercatorBounds::ToLatLon(m_junctions.back().GetPoint());
    LOG(LERROR,
        ("Invalid speed m_forwardSpeed:", m_forwardSpeed, "m_backwardSpeed:", m_backwardSpeed,
         "mwm:", id.GetMwmName(), ", featureId:", id.m_index, ", begin:", begin, "end:", end));
    m_valid = false;
  }
}

SpeedKMpH const & RoadGeometry::GetSpeed(bool forward) const
{
  return forward ? m_forwardSpeed : m_backwardSpeed;
}

double RoadGeometry::GetRoadLengthM() const
{
  double lenM = 0.0;
  for (size_t i = 1; i < GetPointsCount(); ++i)
  {
    lenM +=
        MercatorBounds::DistanceOnEarth(m_junctions[i - 1].GetPoint(), m_junctions[i].GetPoint());
  }

  return lenM;
}

// Geometry ----------------------------------------------------------------------------------------
Geometry::Geometry(unique_ptr<GeometryLoader> loader)
    : m_loader(move(loader))
    , m_featureIdToRoad(make_unique<FifoCache<uint32_t, RoadGeometry>>(
        kRoadsCacheSize,
        [this](uint32_t featureId, RoadGeometry & road) { m_loader->Load(featureId, road); }))
{
  CHECK(m_loader, ());
}

RoadGeometry const & Geometry::GetRoad(uint32_t featureId)
{
  ASSERT(m_featureIdToRoad, ());
  ASSERT(m_loader, ());

  return m_featureIdToRoad->GetValue(featureId);
}

// static
unique_ptr<GeometryLoader> GeometryLoader::Create(DataSource const & dataSource,
                                                  MwmSet::MwmHandle const & handle,
                                                  shared_ptr<VehicleModelInterface> vehicleModel,
                                                  AttrLoader && attrLoader,
                                                  bool loadAltitudes)
{
  CHECK(handle.IsAlive(), ());
  return make_unique<GeometryLoaderImpl>(dataSource, handle, vehicleModel, move(attrLoader),
                                         loadAltitudes);
}

// static
unique_ptr<GeometryLoader> GeometryLoader::CreateFromFile(string const & fileName,
                                                          shared_ptr<VehicleModelInterface> vehicleModel)
{
  return make_unique<FileGeometryLoader>(fileName, vehicleModel);
}
}  // namespace routing
<commit_msg>[routing] Crash fix. Handling an edge case if ferry contains only one point.<commit_after>#include "routing/geometry.hpp"

#include "routing/city_roads.hpp"
#include "routing/maxspeeds.hpp"
#include "routing/routing_exceptions.hpp"
#include "routing/routing_options.hpp"

#include "indexer/altitude_loader.hpp"
#include "indexer/classificator.hpp"
#include "indexer/data_source.hpp"
#include "indexer/ftypes_matcher.hpp"

#include "geometry/mercator.hpp"

#include "base/assert.hpp"
#include "base/string_utils.hpp"

#include <algorithm>
#include <string>

using namespace routing;
using namespace std;

namespace
{
// @TODO(bykoianko) Consider setting cache size based on available memory.
// Maximum road geometry cache size in items.
size_t constexpr kRoadsCacheSize = 5000;

double CalcFerryDurationHours(string const & durationHours, double roadLenKm)
{
  // Look for more info: https://confluence.mail.ru/display/MAPSME/Ferries
  // Shortly: the coefs were received from statistic about ferries with durations in OSM.
  double constexpr kIntercept = 0.2490726747447476;
  double constexpr kSlope = 0.02078913;

  if (durationHours.empty())
    return kIntercept + kSlope * roadLenKm;

  double durationH = 0.0;
  CHECK(strings::to_double(durationHours.c_str(), durationH), (durationHours));

  // See: https://confluence.mail.ru/download/attachments/249123157/image2019-8-22_16-15-53.png
  // Shortly: we drop some points: (x: lengthKm, y: durationH), that are upper or lower these two lines.
  double constexpr kUpperBoundIntercept = 4.0;
  double constexpr kUpperBoundSlope = 0.037;
  if (kUpperBoundIntercept + kUpperBoundSlope * roadLenKm - durationH < 0)
    return kIntercept + kSlope * roadLenKm;

  double constexpr kLowerBoundIntercept = -2.0;
  double constexpr kLowerBoundSlope = 0.015;
  if (kLowerBoundIntercept + kLowerBoundSlope * roadLenKm - durationH > 0)
    return kIntercept + kSlope * roadLenKm;

  return durationH;
}

// GeometryLoaderImpl ------------------------------------------------------------------------------
class GeometryLoaderImpl final : public GeometryLoader
{
public:
  GeometryLoaderImpl(DataSource const & dataSource, MwmSet::MwmHandle const & handle,
                     shared_ptr<VehicleModelInterface> vehicleModel,
                     AttrLoader attrLoader, bool loadAltitudes);

  // GeometryLoader overrides:
  void Load(uint32_t featureId, RoadGeometry & road) override;

private:
  shared_ptr<VehicleModelInterface> m_vehicleModel;
  AttrLoader m_attrLoader;
  FeaturesLoaderGuard m_guard;
  string const m_country;
  feature::AltitudeLoader m_altitudeLoader;
  bool const m_loadAltitudes;
};

GeometryLoaderImpl::GeometryLoaderImpl(DataSource const & dataSource,
                                       MwmSet::MwmHandle const & handle,
                                       shared_ptr<VehicleModelInterface> vehicleModel,
                                       AttrLoader attrLoader, bool loadAltitudes)
  : m_vehicleModel(move(vehicleModel))
  , m_attrLoader(move(attrLoader))
  , m_guard(dataSource, handle.GetId())
  , m_country(handle.GetInfo()->GetCountryName())
  , m_altitudeLoader(dataSource, handle.GetId())
  , m_loadAltitudes(loadAltitudes)
{
  CHECK(handle.IsAlive(), ());
  CHECK(m_vehicleModel, ());
  CHECK(m_attrLoader.m_cityRoads, ());
  CHECK(m_attrLoader.m_maxspeeds, ());
}

void GeometryLoaderImpl::Load(uint32_t featureId, RoadGeometry & road)
{
  auto feature = m_guard.GetFeatureByIndex(featureId);
  if (!feature)
    MYTHROW(RoutingException, ("Feature", featureId, "not found in ", m_country));

  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);

  feature::TAltitudes const * altitudes = nullptr;
  if (m_loadAltitudes)
    altitudes = &(m_altitudeLoader.GetAltitudes(featureId, feature->GetPointsCount()));

  road.Load(*m_vehicleModel, *feature, altitudes, m_attrLoader.m_cityRoads->IsCityRoad(featureId),
            m_attrLoader.m_maxspeeds->GetMaxspeed(featureId));
  m_altitudeLoader.ClearCache();
}

// FileGeometryLoader ------------------------------------------------------------------------------
class FileGeometryLoader final : public GeometryLoader
{
public:
  FileGeometryLoader(string const & fileName, shared_ptr<VehicleModelInterface> vehicleModel);

  // GeometryLoader overrides:
  void Load(uint32_t featureId, RoadGeometry & road) override;

private:
  FeaturesVectorTest m_featuresVector;
  CityRoads m_cityRoads;
  Maxspeeds m_maxspeeds;
  shared_ptr<VehicleModelInterface> m_vehicleModel;
};

FileGeometryLoader::FileGeometryLoader(string const & fileName,
                                       shared_ptr<VehicleModelInterface> vehicleModel)
  : m_featuresVector(FilesContainerR(make_unique<FileReader>(fileName)))
  , m_vehicleModel(vehicleModel)
{
  auto const cont = FilesContainerR(make_unique<FileReader>(fileName));

  try
  {
    if (cont.IsExist(CITY_ROADS_FILE_TAG))
      LoadCityRoads(fileName, cont.GetReader(CITY_ROADS_FILE_TAG), m_cityRoads);

    if (cont.IsExist(MAXSPEEDS_FILE_TAG))
      LoadMaxspeeds(cont.GetReader(MAXSPEEDS_FILE_TAG), m_maxspeeds);
  }
  catch (Reader::OpenException const & e)
  {
    LOG(LERROR, ("File", cont.GetFileName(), "Error while reading", CITY_ROADS_FILE_TAG, "or",
                 MAXSPEEDS_FILE_TAG, "section.", e.Msg()));
  }

  CHECK(m_vehicleModel, ());
}

void FileGeometryLoader::Load(uint32_t featureId, RoadGeometry & road)
{
  auto feature = m_featuresVector.GetVector().GetByIndex(featureId);
  CHECK(feature, ());
  feature->ParseGeometry(FeatureType::BEST_GEOMETRY);
  // Note. If FileGeometryLoader is used for generation cross mwm section for bicycle or
  // pedestrian routing |altitudes| should be used here.
  road.Load(*m_vehicleModel, *feature, nullptr /* altitudes */, m_cityRoads.IsCityRoad(featureId),
            m_maxspeeds.GetMaxspeed(featureId));
}
}  // namespace

namespace routing
{
// RoadGeometry ------------------------------------------------------------------------------------
RoadGeometry::RoadGeometry(bool oneWay, double weightSpeedKMpH, double etaSpeedKMpH,
                           Points const & points)
  : m_forwardSpeed{weightSpeedKMpH, etaSpeedKMpH}
  , m_backwardSpeed(m_forwardSpeed)
  , m_isOneWay(oneWay)
  , m_valid(true)
{
  ASSERT_GREATER(weightSpeedKMpH, 0.0, ());
  ASSERT_GREATER(etaSpeedKMpH, 0.0, ());

  m_junctions.reserve(points.size());
  for (auto const & point : points)
    m_junctions.emplace_back(point, feature::kDefaultAltitudeMeters);
}

void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType & feature,
                        feature::TAltitudes const * altitudes, bool inCity, Maxspeed const & maxspeed)
{
  CHECK(altitudes == nullptr || altitudes->size() == feature.GetPointsCount(), ());

  m_valid = vehicleModel.IsRoad(feature);
  m_isOneWay = vehicleModel.IsOneWay(feature);
  m_forwardSpeed = vehicleModel.GetSpeed(feature, {true /* forward */, inCity, maxspeed});
  m_backwardSpeed = vehicleModel.GetSpeed(feature, {false /* forward */, inCity, maxspeed});
  m_highwayType = vehicleModel.GetHighwayType(feature);
  m_isPassThroughAllowed = vehicleModel.IsPassThroughAllowed(feature);

  feature::TypesHolder types(feature);
  auto const & optionsClassfier = RoutingOptionsClassifier::Instance();
  for (uint32_t type : types)
  {
    if (auto const it = optionsClassfier.Get(type))
      m_routingOptions.Add(*it);
  }

  m_junctions.clear();
  m_junctions.reserve(feature.GetPointsCount());
  for (size_t i = 0; i < feature.GetPointsCount(); ++i)
  {
    m_junctions.emplace_back(feature.GetPoint(i),
                             altitudes ? (*altitudes)[i] : feature::kDefaultAltitudeMeters);
  }

  if (m_routingOptions.Has(RoutingOptions::Road::Ferry))
  {
    auto const durationHours = feature.GetMetadata().Get(feature::Metadata::FMD_DURATION);
    auto const roadLenKm = GetRoadLengthM() / 1000.0;
    double durationH = CalcFerryDurationHours(durationHours, roadLenKm);

    CHECK(!base::AlmostEqualAbs(durationH, 0.0, 1e-5), (durationH));

    if (roadLenKm != 0.0)
    {
      m_forwardSpeed = m_backwardSpeed =
          SpeedKMpH(std::min(vehicleModel.GetMaxWeightSpeed(), roadLenKm / durationH));
    }
  }

  if (m_valid && (!m_forwardSpeed.IsValid() || !m_backwardSpeed.IsValid()))
  {
    auto const & id = feature.GetID();
    CHECK(!m_junctions.empty(), ("mwm:", id.GetMwmName(), ", featureId:", id.m_index));
    auto const begin = MercatorBounds::ToLatLon(m_junctions.front().GetPoint());
    auto const end = MercatorBounds::ToLatLon(m_junctions.back().GetPoint());
    LOG(LERROR,
        ("Invalid speed m_forwardSpeed:", m_forwardSpeed, "m_backwardSpeed:", m_backwardSpeed,
         "mwm:", id.GetMwmName(), ", featureId:", id.m_index, ", begin:", begin, "end:", end));
    m_valid = false;
  }
}

SpeedKMpH const & RoadGeometry::GetSpeed(bool forward) const
{
  return forward ? m_forwardSpeed : m_backwardSpeed;
}

double RoadGeometry::GetRoadLengthM() const
{
  double lenM = 0.0;
  for (size_t i = 1; i < GetPointsCount(); ++i)
  {
    lenM +=
        MercatorBounds::DistanceOnEarth(m_junctions[i - 1].GetPoint(), m_junctions[i].GetPoint());
  }

  return lenM;
}

// Geometry ----------------------------------------------------------------------------------------
Geometry::Geometry(unique_ptr<GeometryLoader> loader)
    : m_loader(move(loader))
    , m_featureIdToRoad(make_unique<FifoCache<uint32_t, RoadGeometry>>(
        kRoadsCacheSize,
        [this](uint32_t featureId, RoadGeometry & road) { m_loader->Load(featureId, road); }))
{
  CHECK(m_loader, ());
}

RoadGeometry const & Geometry::GetRoad(uint32_t featureId)
{
  ASSERT(m_featureIdToRoad, ());
  ASSERT(m_loader, ());

  return m_featureIdToRoad->GetValue(featureId);
}

// static
unique_ptr<GeometryLoader> GeometryLoader::Create(DataSource const & dataSource,
                                                  MwmSet::MwmHandle const & handle,
                                                  shared_ptr<VehicleModelInterface> vehicleModel,
                                                  AttrLoader && attrLoader,
                                                  bool loadAltitudes)
{
  CHECK(handle.IsAlive(), ());
  return make_unique<GeometryLoaderImpl>(dataSource, handle, vehicleModel, move(attrLoader),
                                         loadAltitudes);
}

// static
unique_ptr<GeometryLoader> GeometryLoader::CreateFromFile(string const & fileName,
                                                          shared_ptr<VehicleModelInterface> vehicleModel)
{
  return make_unique<FileGeometryLoader>(fileName, vehicleModel);
}
}  // namespace routing
<|endoftext|>


<commit_before>#include "KinectStreamer.hpp"
#include <libfreenect2/libfreenect2.hpp>
#include <libfreenect2/frame_listener_impl.h>
#include <libfreenect2/registration.h>
#include "FAST/Data/Image.hpp"
#include "FAST/Data/PointSet.hpp"

namespace fast {

KinectStreamer::KinectStreamer() {
    createOutputPort<Image>(0, OUTPUT_DYNAMIC); // RGB
    createOutputPort<Image>(1, OUTPUT_DYNAMIC); // Depth image
    createOutputPort<PointSet>(2, OUTPUT_DYNAMIC); // Point cloud
    mNrOfFrames = 0;
    mHasReachedEnd = false;
    mFirstFrameIsInserted = false;
    mIsModified = true;
}

void KinectStreamer::execute() {
    getOutputData<Image>(0)->setStreamer(mPtr.lock());
    getOutputData<Image>(1)->setStreamer(mPtr.lock());
    getOutputData<Image>(2)->setStreamer(mPtr.lock());
    if(!mStreamIsStarted) {
        // Check that first frame exists before starting streamer

        mStreamIsStarted = true;
        mStop = false;
        mThread = new std::thread(std::bind(&KinectStreamer::producerStream, this));
    }

    // Wait here for first frame
    std::unique_lock<std::mutex> lock(mFirstFrameMutex);
    while(!mFirstFrameIsInserted) {
        mFirstFrameCondition.wait(lock);
    }
}

void KinectStreamer::producerStream() {
    libfreenect2::Freenect2 freenect2;
    libfreenect2::Freenect2Device *dev = 0;
    libfreenect2::PacketPipeline *pipeline = 0;
    std::string serial = "";

    if(freenect2.enumerateDevices() == 0) {
        throw Exception("Unable to find any Kinect devices");
    }
    if(serial == "") {
        serial = freenect2.getDefaultDeviceSerialNumber();
    }
    pipeline = new libfreenect2::OpenGLPacketPipeline();
    dev = freenect2.openDevice(serial, pipeline);

    int types = libfreenect2::Frame::Color | libfreenect2::Frame::Ir | libfreenect2::Frame::Depth;
    libfreenect2::SyncMultiFrameListener listener(types);
    libfreenect2::FrameMap frames;
    dev->setColorFrameListener(&listener);
    dev->setIrAndDepthFrameListener(&listener);

    if(!dev->start())
        throw Exception("Failed to start Kinect device streaming");

    reportInfo() << "Kinect device serial: " << dev->getSerialNumber() << reportEnd();
    reportInfo() << "Kinect device firmware: " << dev->getFirmwareVersion() << reportEnd();

    libfreenect2::Registration *registration = new libfreenect2::Registration(dev->getIrCameraParams(),
                                                                              dev->getColorCameraParams());
    libfreenect2::Frame undistorted(512, 424, 4), registered(512, 424, 4);

    while(true) {
        {
            // Check if stop signal is sent
            std::unique_lock<std::mutex> lock(mStopMutex);
            if(mStop) {
                mStreamIsStarted = false;
                mFirstFrameIsInserted = false;
                mHasReachedEnd = false;
                break;
            }
        }
        if(!listener.waitForNewFrame(frames, 10 * 1000)) { // 10 seconds
            throw Exception("Kinect streaming timeout");
        }
        libfreenect2::Frame *rgb = frames[libfreenect2::Frame::Color];
        libfreenect2::Frame *ir = frames[libfreenect2::Frame::Ir];
        libfreenect2::Frame *depth = frames[libfreenect2::Frame::Depth];

        registration->apply(rgb, depth, &undistorted, &registered);

        float* depth_data = (float*)undistorted.data;
        unsigned char* rgb_data = (unsigned char*)registered.data;

        Image::pointer depthImage = Image::New();
        depthImage->create(512, 424, TYPE_FLOAT, 1, depth_data);

        Image::pointer rgbImage = Image::New();
        if(rgb->format == libfreenect2::Frame::Format::BGRX) {
            // Have to swap B and R channel
            for(int i = 0; i < 512*424; ++i) {
                uchar blue = rgb_data[i*4];
                rgb_data[i*4] = rgb_data[i*4+2];
                rgb_data[i*4+2] = blue;
            }
        }
        rgbImage->create(512, 424, TYPE_UINT8, 4, rgb_data);

        // Create point cloud
        std::vector<Vector3f> points;
        for(int r=0; r<424; ++r) {
            for(int c = 0; c < 512; ++c) {
                float x, y, z, color;
                registration->getPointXYZRGB(&undistorted, &registered, r, c, x, y, z, color);
                if(!std::isnan(x)) {
                    Vector3f point(x*1000, y*1000, z*1000);
                    //std::cout << point.transpose() << std::endl;
                    points.push_back(point);
                }
            }
        }
        PointSet::pointer cloud = PointSet::New();
        cloud->create(points);

        DynamicData::pointer ddRGB = getOutputData<Image>(0);
        DynamicData::pointer ddDepth = getOutputData<Image>(1);
        DynamicData::pointer ddPoint = getOutputData<PointSet>(2);
        if(ddRGB.isValid() && ddDepth.isValid()) {
            try {
                ddRGB->addFrame(rgbImage);
                ddDepth->addFrame(depthImage);
                ddPoint->addFrame(cloud);
            } catch(NoMoreFramesException &e) {
                throw e;
            } catch(Exception &e) {
                reportInfo() << "streamer has been deleted, stop" << Reporter::end;
                listener.release(frames);
                break;
            }
            if(!mFirstFrameIsInserted) {
                {
                    std::lock_guard<std::mutex> lock(mFirstFrameMutex);
                    mFirstFrameIsInserted = true;
                }
                mFirstFrameCondition.notify_one();
            }
        } else {
            reportInfo() << "DynamicImage object destroyed, stream can stop." << Reporter::end;
            listener.release(frames);
            break;
        }
        mNrOfFrames++;
        listener.release(frames);
    }

    reportInfo() << "Stopping kinect streamer" << Reporter::end;
    dev->stop();
    dev->close();

    // TODO proper cleanup
}

bool KinectStreamer::hasReachedEnd() const {
    return mHasReachedEnd;
}

uint KinectStreamer::getNrOfFrames() const {
    return mNrOfFrames;
}

KinectStreamer::~KinectStreamer() {
    if(mStreamIsStarted) {
        stop();
        mThread->join();
    }
}

void KinectStreamer::stop() {
    std::unique_lock<std::mutex> lock(mStopMutex);
    mStop = true;
}

}<commit_msg>Delete a resource in kinect streamer<commit_after>#include "KinectStreamer.hpp"
#include <libfreenect2/libfreenect2.hpp>
#include <libfreenect2/frame_listener_impl.h>
#include <libfreenect2/registration.h>
#include "FAST/Data/Image.hpp"
#include "FAST/Data/PointSet.hpp"

namespace fast {

KinectStreamer::KinectStreamer() {
    createOutputPort<Image>(0, OUTPUT_DYNAMIC); // RGB
    createOutputPort<Image>(1, OUTPUT_DYNAMIC); // Depth image
    createOutputPort<PointSet>(2, OUTPUT_DYNAMIC); // Point cloud
    mNrOfFrames = 0;
    mHasReachedEnd = false;
    mFirstFrameIsInserted = false;
    mIsModified = true;
}

void KinectStreamer::execute() {
    getOutputData<Image>(0)->setStreamer(mPtr.lock());
    getOutputData<Image>(1)->setStreamer(mPtr.lock());
    getOutputData<Image>(2)->setStreamer(mPtr.lock());
    if(!mStreamIsStarted) {
        // Check that first frame exists before starting streamer

        mStreamIsStarted = true;
        mStop = false;
        mThread = new std::thread(std::bind(&KinectStreamer::producerStream, this));
    }

    // Wait here for first frame
    std::unique_lock<std::mutex> lock(mFirstFrameMutex);
    while(!mFirstFrameIsInserted) {
        mFirstFrameCondition.wait(lock);
    }
}

void KinectStreamer::producerStream() {
    libfreenect2::Freenect2 freenect2;
    libfreenect2::Freenect2Device *dev = 0;
    libfreenect2::PacketPipeline *pipeline = 0;
    std::string serial = "";

    if(freenect2.enumerateDevices() == 0) {
        throw Exception("Unable to find any Kinect devices");
    }
    if(serial == "") {
        serial = freenect2.getDefaultDeviceSerialNumber();
    }
    pipeline = new libfreenect2::OpenGLPacketPipeline();
    dev = freenect2.openDevice(serial, pipeline);

    int types = libfreenect2::Frame::Color | libfreenect2::Frame::Ir | libfreenect2::Frame::Depth;
    libfreenect2::SyncMultiFrameListener listener(types);
    libfreenect2::FrameMap frames;
    dev->setColorFrameListener(&listener);
    dev->setIrAndDepthFrameListener(&listener);

    if(!dev->start())
        throw Exception("Failed to start Kinect device streaming");

    reportInfo() << "Kinect device serial: " << dev->getSerialNumber() << reportEnd();
    reportInfo() << "Kinect device firmware: " << dev->getFirmwareVersion() << reportEnd();

    libfreenect2::Registration *registration = new libfreenect2::Registration(dev->getIrCameraParams(),
                                                                              dev->getColorCameraParams());
    libfreenect2::Frame undistorted(512, 424, 4), registered(512, 424, 4);

    while(true) {
        {
            // Check if stop signal is sent
            std::unique_lock<std::mutex> lock(mStopMutex);
            if(mStop) {
                mStreamIsStarted = false;
                mFirstFrameIsInserted = false;
                mHasReachedEnd = false;
                break;
            }
        }
        if(!listener.waitForNewFrame(frames, 10 * 1000)) { // 10 seconds
            throw Exception("Kinect streaming timeout");
        }
        libfreenect2::Frame *rgb = frames[libfreenect2::Frame::Color];
        libfreenect2::Frame *ir = frames[libfreenect2::Frame::Ir];
        libfreenect2::Frame *depth = frames[libfreenect2::Frame::Depth];

        registration->apply(rgb, depth, &undistorted, &registered);

        float* depth_data = (float*)undistorted.data;
        unsigned char* rgb_data = (unsigned char*)registered.data;

        Image::pointer depthImage = Image::New();
        depthImage->create(512, 424, TYPE_FLOAT, 1, depth_data);

        Image::pointer rgbImage = Image::New();
        if(rgb->format == libfreenect2::Frame::Format::BGRX) {
            // Have to swap B and R channel
            for(int i = 0; i < 512*424; ++i) {
                uchar blue = rgb_data[i*4];
                rgb_data[i*4] = rgb_data[i*4+2];
                rgb_data[i*4+2] = blue;
            }
        }
        rgbImage->create(512, 424, TYPE_UINT8, 4, rgb_data);

        // Create point cloud
        std::vector<Vector3f> points;
        for(int r=0; r<424; ++r) {
            for(int c = 0; c < 512; ++c) {
                float x, y, z, color;
                registration->getPointXYZRGB(&undistorted, &registered, r, c, x, y, z, color);
                if(!std::isnan(x)) {
                    Vector3f point(x*1000, y*1000, z*1000);
                    //std::cout << point.transpose() << std::endl;
                    points.push_back(point);
                }
            }
        }
        PointSet::pointer cloud = PointSet::New();
        cloud->create(points);

        DynamicData::pointer ddRGB = getOutputData<Image>(0);
        DynamicData::pointer ddDepth = getOutputData<Image>(1);
        DynamicData::pointer ddPoint = getOutputData<PointSet>(2);
        if(ddRGB.isValid() && ddDepth.isValid()) {
            try {
                ddRGB->addFrame(rgbImage);
                ddDepth->addFrame(depthImage);
                ddPoint->addFrame(cloud);
            } catch(NoMoreFramesException &e) {
                throw e;
            } catch(Exception &e) {
                reportInfo() << "streamer has been deleted, stop" << Reporter::end;
                listener.release(frames);
                break;
            }
            if(!mFirstFrameIsInserted) {
                {
                    std::lock_guard<std::mutex> lock(mFirstFrameMutex);
                    mFirstFrameIsInserted = true;
                }
                mFirstFrameCondition.notify_one();
            }
        } else {
            reportInfo() << "DynamicImage object destroyed, stream can stop." << Reporter::end;
            listener.release(frames);
            break;
        }
        mNrOfFrames++;
        listener.release(frames);
    }

    reportInfo() << "Stopping kinect streamer" << Reporter::end;
    dev->stop();
    dev->close();
    delete dev;
}

bool KinectStreamer::hasReachedEnd() const {
    return mHasReachedEnd;
}

uint KinectStreamer::getNrOfFrames() const {
    return mNrOfFrames;
}

KinectStreamer::~KinectStreamer() {
    if(mStreamIsStarted) {
        stop();
        mThread->join();
    }
}

void KinectStreamer::stop() {
    std::unique_lock<std::mutex> lock(mStopMutex);
    mStop = true;
}

}<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <vector>
#include <queue>
#include <stdio.h>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>

using namespace std;
using namespace boost;

class Connectors    //abstract base class so we can dynamically call run
{
    public:
        virtual bool run(bool state) = 0;
};

class Semicolon : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    Semicolon(vector<string> v) : vctr(50)  //constructor creates char* vector
    {                                       //which stores one command+params
        vctr.reserve(v.size());             //in a semicolon object
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL);   //makes sure the command ends with a null char
    }                           //so execvp can determine the end
    virtual bool run(bool state)
    {
        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //returns the state accordingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

class And : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    And(vector<string> v) : vctr(50)
    {
        vctr.reserve(v.size()); //store one command+param of type And
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL); //end with null char
    }
    virtual bool run(bool state)
    {
        if (state != 1) //return if the previous command failed
        {
            return state;
        }

        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //outputs the state accordingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

class Or : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    Or(vector<string> v) : vctr(50) //stores one command+params of type Or
    {
        vctr.reserve(v.size());
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL); //end with null
    }
    virtual bool run(bool state)
    {
        if (state != 0) //return if the previous command succeeded
        {
            return state;
        }

        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //outputs the state accodingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

int main()
{
    int w = 0;
    while (w == 0)
    {
        // extra credit part
        char *username;
        int host;
        if ((username = getlogin()) != NULL) // get the username
        {
            char name[101];
            int len = 100;
            if ((host = gethostname(name, len)) == 0) // get the hostname
            {
                cout << username << "@" << name << "$ ";
            }
            else
            {
                 cout << "$ ";           //outputs terminal $
            }
        }
        else
        {
            cout << "$ ";
        }

        string input;
        getline(cin, input);    //gets user input

        //containers we'll use for storage
        vector< vector<string> > v;
        vector<string> t;
        vector<Connectors*> objects;
        queue<string> q;

        int column = 0;

        //creates tokenizer and char separator to parse input
        typedef tokenizer<char_separator<char> > tokenizer;
        char_separator<char> sep(" ", ";#|&");
        tokenizer tokens(input, sep);

        bool lastVal = 0;
        for (tokenizer::iterator check = tokens.begin(); check != tokens.end(); ++check)
        {
            tokenizer::iterator count = check;
            ++count;
            if (count == tokens.end())
            {
                if (*check == "|" || *check == "&")
                {
                    lastVal = 1;
                }
            }
        }

        if (lastVal == 1)
        {
            cout << "end of input cannot be a connector" << endl;
            continue;
        }

        bool flag = 0; //flag to check when to start a new column
        bool wrong = 0;
        //holds commands in a 2d vector

        for (tokenizer::iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
        {
            tokenizer::iterator temp = itr;
            if (*itr == ";")
            {
                ++temp;
                if (temp != tokens.end())
                {
                    if (*temp == *itr)
                    {
                        cout << "cannot have multiple semicolons" << endl;
                        wrong = 1;
                        break;
                    }
                }
                q.push(*itr);
                column = column + 1;
                flag = 0;
            }

            else if ((*itr == "|") || (*itr == "&"))
            {
                ++temp;
                if (*temp != *itr)
                {
                    cout << "cannot enter single connector" << endl;
                    wrong = 1;
                    break;
                }
                ++temp;
                if (*temp == *itr)
                {
                    cout << "cannot enter 3+ connector" << endl;
                    wrong = 1;
                    break;
                }

                q.push(*itr); //pushes connector into queue
                column = column + 1; //increments column
                flag = 0;
                ++itr;  //extra increments itr to not test second connector in pair
            }
            else if (*itr == "#")
            {
                break;          //if there's a comment, break out of loop
            }
            else
            {
                if (!flag)
                {
                    v.push_back(t); //starts a new column
                    v.at(column).push_back(*itr);
                    flag = 1;
                }
                else
                { //push value into position
                    v.at(column).push_back(*itr);
                }
            }
        }

        //checks the contents of v
        //for (unsigned i = 0; i < v.size(); ++i)
        //{
           //for (unsigned j = 0; j < v.at(i).size(); ++j)
           //{
                //cout << v.at(i).at(j);
           //}

        //}

        if (wrong == 1)
        {
            continue;
        }

        //this part of the code creates a temp vector current which holds
        //a single command+param chunk at a time
        //then determines the connector previous to the command its told to run
        //it then creates the corresponding connector class type object
        //and pushes the new object into a vector of Connectors pointers
        bool first = 1;
        vector<string> current;

        for (unsigned i = 0; i < v.size(); ++i)
        {
            for (unsigned j = 0; j < v.at(i).size(); ++j)
            {
                current.push_back(v.at(i).at(j));
            }
            if (!q.empty() && first != 1)
            {
                if (q.front() == ";")
                {
                    objects.push_back(new Semicolon(current));
                }

                if (q.front() == "|")
                {
                    objects.push_back(new Or(current));
                }

                if (q.front() == "&")
                {
                    objects.push_back(new And(current));
                }
                q.pop();
            }
            if (first == 1)
            {
                objects.push_back(new Semicolon(current));
                first = 0;
            }
            current.clear();
        }
        bool beg = 0;
        bool durr = 0;
        //this loop goes through the object vector and calls run on each
        //object, dynamically calling the run of the class type
        //cout << "Size: " << objects.size()  << endl;
        for (unsigned i = 0; i < objects.size(); ++i)
        {
            //cout << "Curr size: " << objects.size() << endl;
            durr = objects.at(i)->run(beg);
            //cout << "State after run: " << durr << endl;
            beg = durr;
        }

        Connectors *curr;
        for (vector<Connectors *>::iterator ptr = objects.begin();
        ptr != objects.end(); ++ptr)
        {
            curr = *ptr;
            delete curr;
        }

    }
    return 0;
}

<commit_msg>destructors<commit_after>#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <vector>
#include <queue>
#include <stdio.h>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>

using namespace std;
using namespace boost;

class Connectors    //abstract base class so we can dynamically call run
{
    public:
        virtual bool run(bool state) = 0;
};

class Semicolon : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    Semicolon(vector<string> v) : vctr(50)  //constructor creates char* vector
    {                                       //which stores one command+params
        vctr.reserve(v.size());             //in a semicolon object
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL);   //makes sure the command ends with a null char
    }
    virtual ~Semicolon()
    {
        for (unsigned i = 0; i < vctr.size(); ++i)
        {
            vctr.pop_back();
        }
    }
                           //so execvp can determine the end
    virtual bool run(bool state)
    {
        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //returns the state accordingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

class And : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    And(vector<string> v) : vctr(50)
    {
        vctr.reserve(v.size()); //store one command+param of type And
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL); //end with null char
    }

    virtual ~And()
    {
        for (unsigned i = 0; i < vctr.size(); ++i)
        {
            vctr.pop_back();
        }
    }

    virtual bool run(bool state)
    {
        if (state != 1) //return if the previous command failed
        {
            return state;
        }

        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //outputs the state accordingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

class Or : public Connectors
{
    private:
       vector<char *> vctr;
    public:
    Or(vector<string> v) : vctr(50) //stores one command+params of type Or
    {
        vctr.reserve(v.size());
        for (unsigned i = 0; i < v.size(); ++i)
        {
            vctr[i] = const_cast<char*>(v[i].c_str());
        }
        vctr.push_back(NULL); //end with null
    }
    virtual ~Or()
    {
        for (unsigned i = 0; i < vctr.size(); ++i)
        {
            vctr.pop_back();
        }
    }

    virtual bool run(bool state)
    {
        if (state != 0) //return if the previous command succeeded
        {
            return state;
        }

        char **pointer = &vctr[0];  //points to vctr we'll use for execvp

        string ex = "exit";
        string p = pointer[0];
        if (p == ex) // check if the command entered is exit
        {
            exit(0);
        }

        pid_t c_pid, pid;
        int status;
        c_pid = fork();

        if (c_pid < 0)      //checks if fork failed
        {
            perror("fork failed");
            state = 0;
            return state;
        }
        else if (c_pid == 0)    //if we're in the child, call execvp
        {
            execvp(pointer[0], pointer);
            perror("execvp failed");
            exit(127);
        }
        else //if in the parent, wait for child to terminate
        {
            //checks if wait fails
            if ((pid = waitpid(c_pid, &status, 0)) < 0)
            {
                perror("wait failed");
                state = 0;
                return state;
            }
            //checks whether the child succeeded or not
            //outputs the state accodingly
            if (status == 0)
            {
                state = 1; //if it succeeded, set the state to true
                return state;
            }
            else
            {
                state = 0;
                return state;
            }
        }
        return 0;
    }
};

int main()
{
    int w = 0;
    while (w == 0)
    {
        // extra credit part
        char *username;
        int host;
        if ((username = getlogin()) != NULL) // get the username
        {
            char name[101];
            int len = 100;
            if ((host = gethostname(name, len)) == 0) // get the hostname
            {
                cout << username << "@" << name << "$ ";
            }
            else
            {
                 cout << "$ ";           //outputs terminal $
            }
        }
        else
        {
            cout << "$ ";
        }

        string input;
        getline(cin, input);    //gets user input

        //containers we'll use for storage
        vector< vector<string> > v;
        vector<string> t;
        vector<Connectors*> objects;
        queue<string> q;

        int column = 0;

        //creates tokenizer and char separator to parse input
        typedef tokenizer<char_separator<char> > tokenizer;
        char_separator<char> sep(" ", ";#|&");
        tokenizer tokens(input, sep);

        bool lastVal = 0;
        for (tokenizer::iterator check = tokens.begin(); check != tokens.end(); ++check)
        {
            tokenizer::iterator count = check;
            ++count;
            if (count == tokens.end())
            {
                if (*check == "|" || *check == "&")
                {
                    lastVal = 1;
                }
            }
        }

        if (lastVal == 1)
        {
            cout << "end of input cannot be a connector" << endl;
            continue;
        }

        bool flag = 0; //flag to check when to start a new column
        bool wrong = 0;
        //holds commands in a 2d vector

        for (tokenizer::iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
        {
            tokenizer::iterator temp = itr;
            if (*itr == ";")
            {
                ++temp;
                if (temp != tokens.end())
                {
                    if (*temp == *itr)
                    {
                        cout << "cannot have multiple semicolons" << endl;
                        wrong = 1;
                        break;
                    }
                }
                q.push(*itr);
                column = column + 1;
                flag = 0;
            }

            else if ((*itr == "|") || (*itr == "&"))
            {
                ++temp;
                if (*temp != *itr)
                {
                    cout << "cannot enter single connector" << endl;
                    wrong = 1;
                    break;
                }
                ++temp;
                if (*temp == *itr)
                {
                    cout << "cannot enter 3+ connector" << endl;
                    wrong = 1;
                    break;
                }

                q.push(*itr); //pushes connector into queue
                column = column + 1; //increments column
                flag = 0;
                ++itr;  //extra increments itr to not test second connector in pair
            }
            else if (*itr == "#")
            {
                break;          //if there's a comment, break out of loop
            }
            else
            {
                if (!flag)
                {
                    v.push_back(t); //starts a new column
                    v.at(column).push_back(*itr);
                    flag = 1;
                }
                else
                { //push value into position
                    v.at(column).push_back(*itr);
                }
            }
        }

        //checks the contents of v
        //for (unsigned i = 0; i < v.size(); ++i)
        //{
           //for (unsigned j = 0; j < v.at(i).size(); ++j)
           //{
                //cout << v.at(i).at(j);
           //}

        //}

        if (wrong == 1)
        {
            continue;
        }

        //this part of the code creates a temp vector current which holds
        //a single command+param chunk at a time
        //then determines the connector previous to the command its told to run
        //it then creates the corresponding connector class type object
        //and pushes the new object into a vector of Connectors pointers
        bool first = 1;
        vector<string> current;

        for (unsigned i = 0; i < v.size(); ++i)
        {
            for (unsigned j = 0; j < v.at(i).size(); ++j)
            {
                current.push_back(v.at(i).at(j));
            }
            if (!q.empty() && first != 1)
            {
                if (q.front() == ";")
                {
                    objects.push_back(new Semicolon(current));
                }

                if (q.front() == "|")
                {
                    objects.push_back(new Or(current));
                }

                if (q.front() == "&")
                {
                    objects.push_back(new And(current));
                }
                q.pop();
            }
            if (first == 1)
            {
                objects.push_back(new Semicolon(current));
                first = 0;
            }
            current.clear();
        }
        bool beg = 0;
        bool durr = 0;
        //this loop goes through the object vector and calls run on each
        //object, dynamically calling the run of the class type
        //cout << "Size: " << objects.size()  << endl;
        for (unsigned i = 0; i < objects.size(); ++i)
        {
            //cout << "Curr size: " << objects.size() << endl;
            durr = objects.at(i)->run(beg);
            //cout << "State after run: " << durr << endl;
            beg = durr;
        }

    }
    return 0;
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief FifoQueueBase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-10
 */

#include "distortos/scheduler/FifoQueueBase.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

namespace distortos
{

namespace scheduler
{

/*---------------------------------------------------------------------------------------------------------------------+
| public functions
+---------------------------------------------------------------------------------------------------------------------*/

int FifoQueueBase::popPushImplementation(const SemaphoreFunctor& waitSemaphoreFunctor, const Functor& functor,
		Semaphore& waitSemaphore, Semaphore& postSemaphore, void*& storage)
{
	architecture::InterruptMaskingLock interruptMaskingLock;

	const auto ret = waitSemaphoreFunctor(waitSemaphore);
	if (ret != 0)
		return ret;

	functor(storage);

	if (storage == storageEnd_)
		storage = storageBegin_;

	return postSemaphore.post();
}

}	// namespace scheduler

}	// namespace distortos
<commit_msg>FifoQueueBase.cpp: comment fix<commit_after>/**
 * \file
 * \brief FifoQueueBase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-11
 */

#include "distortos/scheduler/FifoQueueBase.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

namespace distortos
{

namespace scheduler
{

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

int FifoQueueBase::popPushImplementation(const SemaphoreFunctor& waitSemaphoreFunctor, const Functor& functor,
		Semaphore& waitSemaphore, Semaphore& postSemaphore, void*& storage)
{
	architecture::InterruptMaskingLock interruptMaskingLock;

	const auto ret = waitSemaphoreFunctor(waitSemaphore);
	if (ret != 0)
		return ret;

	functor(storage);

	if (storage == storageEnd_)
		storage = storageBegin_;

	return postSemaphore.post();
}

}	// namespace scheduler

}	// namespace distortos
<|endoftext|>